在代号一中从存储中保存和加载图像

Saving and loading Images from the Storage in Codename One

看来我的以下代码没有按预期工作。

以下 class 在模拟器中运行良好,但在真实设备上我注意到该应用程序打开图像需要太多时间:我的意思是第一次加载后没有任何时间优势.

相反,我希望这个 class 应该需要更多时间来第一次打开图像,然后下次应该会快很多(因为缩放后的图像保存到 Storage).

EasyThread 的目的是在缩放期间不阻塞 EDT,因为我有多个图像,总共需要很多秒 cpu。

/**
 * Button useful to show the given Image at the given size.
 *
 * @author Francesco Galgani
 */
public class FixedSizeButton extends Button {

    private final int imageWidth;
    private final int imageHeight;
    private FixedSizeButton instance;
    private Image image;

    /**
     * Creates a Button displaying an Image at the given fixed size; at least
     * one of imageWidth or imageHeight must be specified.
     *
     * @param image
     * @param imageWidth in pixels, can be -1 to automatically resize
     * maintaining the aspect ratio
     * @param imageHeight in pixels, can be -1 to automatically resize
     * maintaining the aspect ratio
     */
    public FixedSizeButton(Image image, String uniqueName, int imageWidth, int imageHeight) {
        this(image, uniqueName, imageWidth, imageHeight, null);
    }

    /**
     * Creates a Button displaying an Image at the given fixed size; at least
     * one of imageWidth or imageHeight must be specified.
     *
     * @param image
     * @param imageWidth in pixels, can be -1 to automatically resize
     * maintaining the aspect ratio
     * @param imageHeight in pixels, can be -1 to automatically resize
     * maintaining the aspect ratio
     * @param uiid
     */
    public FixedSizeButton(Image image, String uniqueName, int imageWidth, int imageHeight, String uiid) {
        this(image, uniqueName, imageWidth, imageHeight, false, uiid);
    }

    /**
     * Creates a Button displaying an Image at the given fixed size; at least
     * one of imageWidth or imageHeight must be specified.
     *
     * @param image
     * @param imageWidth in pixels, can be -1 to automatically resize
     * maintaining the aspect ratio
     * @param imageHeight in pixels, can be -1 to automatically resize
     * maintaining the aspect ratio
     * @param scaledSmallerRatio force the image to maintain the aspect ratio
     * within the given dimension (it requires that both imageWidth and
     * imageHeight are specified)
     * @param uiid
     */
    public FixedSizeButton(Image image, String uniqueName, int imageWidth, int imageHeight, boolean scaledSmallerRatio, String uiid) {
        if (image == null) {
            throw new IllegalArgumentException("image cannot be null");
        }
        if (StringUtilities.isEmptyOrNull(uniqueName)) {
            throw new IllegalArgumentException("image must have an unique name");
        }
        if (imageWidth <= 0 && imageHeight <= 0) {
            throw new IllegalArgumentException("invalid imageWidth and imageHeight");
        }
        this.instance = this;
        setShowEvenIfBlank(true);
        if (uiid != null) {
            super.setUIID(uiid);
        }
        if (imageWidth < 1) {
            imageWidth = image.getWidth() * imageHeight / image.getHeight();
        } else if (imageHeight < 1) {
            imageHeight = image.getHeight() * imageWidth / image.getWidth();
        }
        if (scaledSmallerRatio) {
            float hRatio = ((float) imageHeight) / ((float) image.getHeight());
            float wRatio = ((float) imageWidth) / ((float) image.getWidth());
            if (hRatio < wRatio) {
                imageWidth = (int) (image.getWidth() * hRatio);
            } else {
                imageHeight = (int) (image.getHeight() * wRatio);
            }
        }

        this.imageWidth = imageWidth;
        this.imageHeight = imageHeight;
        String fileName = StringUtilities.replaceAll(uniqueName, ".", "_") + "_" + this.imageWidth + "_" + this.imageHeight + ".jpg";

        this.image = Image.createImage(this.imageWidth, this.imageHeight, 0xFFdddddd);
        this.setIcon(this.image);

        EasyThread scalingThread = EasyThread.start("FixedSizeButton-ScalingImg-" + fileName);
        scalingThread.run(new RunnableWithResult<Image>() {
            @Override
            public void run(SuccessCallback<Image> onSuccess) {
                try {
                    if (Storage.getInstance().exists(fileName)) {
                        Image scaledImg = Image.createImage(Storage.getInstance().createInputStream(fileName));
                        onSuccess.onSucess(scaledImg);
                    } else {
                        Image scaledImg = image.scaled(instance.imageWidth, instance.imageHeight);
                        ImageIO.getImageIO().save(scaledImg, Storage.getInstance().createOutputStream(fileName), ImageIO.FORMAT_JPEG, 0.9f);
                        onSuccess.onSucess(scaledImg);
                    }
                } catch (IOException ex) {
                    Log.e(ex);
                    SendLog.sendLogAsync();
                }
            }
        }, new SuccessCallback<Image>() {
            @Override
            public void onSucess(Image image) {
                instance.image = image;
                instance.setIcon(instance.image);
            }
        });

    }

    @Override
    public Dimension calcPreferredSize() {
        int width = imageWidth + this.getStyle().getPaddingLeftNoRTL() + this.getStyle().getPaddingRightNoRTL();
        int height = imageHeight + this.getStyle().getPaddingTop() + this.getStyle().getPaddingBottom();
        return new Dimension(width, height);
    }

    @Override
    public void setText(String text) {
        throw new IllegalStateException("Not supported");
    }

}

我猜这里有问题:

if (Storage.getInstance().exists(fileName)) {
                        Image scaledImg = Image.createImage(Storage.getInstance().createInputStream(fileName));
                        onSuccess.onSucess(scaledImg);
                    } else {
                        Image scaledImg = image.scaled(instance.imageWidth, instance.imageHeight);
                        ImageIO.getImageIO().save(scaledImg, Storage.getInstance().createOutputStream(fileName), ImageIO.FORMAT_JPEG, 0.9f);
                        onSuccess.onSucess(scaledImg);
                    }

最后,我假设instance.setIcon(instance.image);是在EDT中调用的,image.scaled是在非EDT的线程中调用的:如果我错了请指正。

创建一个 EasyThread 很昂贵。您应该创建一个,然后像您一样使用 run 方法。成功回调应该在美国东部时间。您可以使用 isEDT() 方法轻松验证它。

我建议添加一些日志记录以确保正确缓存和加载图像。