模拟器中的InfiniteScrollAdapter中的URLImage显示NPE(CodenameOne)

时间:2017-02-28 05:25:41

标签: java codenameone

我的应用通过InfiniteScrollAdapterURLImage填充了URLImage.ImageAdapter个图片。

在模拟器(Iphone3GS或Xoom或GoogleNexus7)中,虽然文件确实存在于服务器上,但第一次出现InfiniteScrollAdapter时会显示NPE。

请注意:在此测试中,数据库中只有一个条目。因此,在下图中您应该看到的是同一行(图像+文本)重复3次。

NPE in InfiniteScrollAdapter

请注意,未显示图标中的订单可能不同

NPE with different order in the undisplayed icons

我用来下载图片的代码是:

Image tempPlaceholder = Image.createImage(
            ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
            ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
            ParametresGeneraux.accentColor);
    Graphics gr = tempPlaceholder.getGraphics();
    gr.setAntiAliased(true);
    gr.setColor(ParametresGeneraux.accentColor);
    gr.fillArc(0, 0, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, 0, 360);

    EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);

    final Image reportImage = URLImage.createToStorage(
                            roundPlaceholder,
                            photoFilenameInStorage,
                            currentReport.getPhotoPath(),
                            ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
                    );

这是被覆盖的imageAdapter方法:

    public final static URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
    @Override
    public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
        final Image[] tmp = new Image[1];

        if (!Display.getInstance().isEdt()) {
            // The image scaling has to be called from EDT
            Display.getInstance().callSeriallyAndWait(() -> {

                tmp[0] = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
                if (tmp[0].getWidth() > placeholderImage.getWidth()) {
                    int diff = tmp[0].getWidth() - placeholderImage.getWidth();
                    int x = diff / 2;
                    tmp[0] = tmp[0].subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
                } else if (tmp[0].getHeight() > placeholderImage.getHeight()) {
                    int diff = tmp[0].getHeight() - placeholderImage.getHeight();
                    int y = diff / 2;
                    tmp[0] = tmp[0].subImage(0, y, Math.min(placeholderImage.getWidth(), tmp[0].getWidth()),
                            Math.min(placeholderImage.getHeight(), tmp[0].getHeight()), true);
                }
            });
        } else {
            tmp[0] = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
            if (tmp[0].getWidth() > placeholderImage.getWidth()) {
                int diff = tmp[0].getWidth() - placeholderImage.getWidth();
                int x = diff / 2;
                tmp[0] = tmp[0].subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
            } else if (tmp[0].getHeight() > placeholderImage.getHeight()) {
                int diff = tmp[0].getHeight() - placeholderImage.getHeight();
                int y = diff / 2;
                tmp[0] = tmp[0].subImage(0, y, Math.min(placeholderImage.getWidth(), tmp[0].getWidth()),
                        Math.min(placeholderImage.getHeight(), tmp[0].getHeight()), true);
            }
        }

        EncodedImage[] image2Return = new EncodedImage[1];
        if (!Display.getInstance().isEdt()) {
            // The image scaling has to be called from EDT
            Display.getInstance().callSeriallyAndWait(() -> {
                Image roundMask = Image.createImage(tmp[0].getWidth(), tmp[0].getHeight(), 0xff000000);
                Graphics gr = roundMask.getGraphics();
                gr.setColor(0xffffff);

                gr.fillArc(0, 0, tmp[0].getWidth(), tmp[0].getHeight(), 0, 360);
                Object mask = roundMask.createMask();
                tmp[0] = tmp[0].applyMask(mask);
                image2Return[0] = EncodedImage.createFromImage(tmp[0], false);
            });
        } else {
            Image roundMask = Image.createImage(tmp[0].getWidth(), tmp[0].getHeight(), 0xff000000);
            Graphics gr = roundMask.getGraphics();
            gr.setColor(0xffffff);

            gr.fillArc(0, 0, tmp[0].getWidth(), tmp[0].getHeight(), 0, 360);
            Object mask = roundMask.createMask();
            tmp[0] = tmp[0].applyMask(mask);
            image2Return[0] = EncodedImage.createFromImage(tmp[0], false);
        }

        return image2Return[0];

    } 

在堆栈跟踪中,NPE似乎源于被覆盖的URLImage.ImageAdapter

  

java.lang.IllegalArgumentException:为给定的创建图像失败   长度为0的图像数据   com.codename1.ui.Image.createImage(Image.java:654)at   com.codename1.ui.EncodedImage.getInternal(EncodedImage.java:365)at   com.codename1.ui.EncodedImage.getInternalImpl(EncodedImage.java:340)   在com.codename1.ui.EncodedImage.getHeight(EncodedImage.java:522)at   com.codename1.ui.Image.scaledLargerRatio(Image.java:899)at   com.my.application.ParametresGeneraux $ 1.lambda $ adaptImage $ 0(ParametresGeneraux.java:564)   在com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:95)at   com.codename1.ui.Display.processSerialCalls(Display.java:1154)at   com.codename1.ui.Display.edtLoopImpl(Display.java:1098)at   com.codename1.ui.Display.invokeAndBlock(Display.java:1207)at   com.codename1.ui.Display.invokeAndBlock(Display.java:1244)at   com.codename1.ui.URLImage $ DownloadCompleted.actionPerformed(URLImage.java:233)   在com.codename1.ui.URLImage $ 4.onSucess(URLImage.java:301)at   com.codename1.ui.URLImage $ 4.onSucess(URLImage.java:297)at   com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53)   在com.codename1.ui.Display.processSerialCalls(Display.java:1154)at   com.codename1.ui.Display.edtLoopImpl(Display.java:1098)at   com.codename1.ui.Display.mainEDTLoop(Display.java:999)at   com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)at at   com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)   [EDT] 0:0:0,1 - 代号修改:   e5c43877074c18b4b5c7748d000e5cfac75ab749 2318

     

[EDT] 0:0:0,1 - 异常:java.lang.NullPointerException - null   java.lang.NullPointerException at   com.codename1.impl.javase.JavaSEPort.scale(JavaSEPort.java:3996)at at   com.codename1.ui.Image.scale(Image.java:1007)at   com.codename1.ui.Image.scaledImpl(Image.java:953)at   com.codename1.ui.Image.scaled(Image.java:918)at   com.codename1.impl.javase.JavaSEPort $ 71.save(JavaSEPort.java:7659)at at   com.codename1.ui.EncodedImage.scaledEncoded(EncodedImage.java:626)at at   com.codename1.ui.EncodedImage.scaled(EncodedImage.java:653)at   com.codename1.ui.Image.scaledLargerRatio(Image.java:904)at   com.my.application.ParametresGeneraux $ 1.lambda $ adaptImage $ 0(ParametresGeneraux.java:564)   在com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:95)at   com.codename1.ui.Display.processSerialCalls(Display.java:1154)at   com.codename1.ui.Display.edtLoopImpl(Display.java:1098)at   com.codename1.ui.Display.invokeAndBlock(Display.java:1207)at   com.codename1.ui.Display.invokeAndBlock(Display.java:1244)at   com.codename1.ui.URLImage $ DownloadCompleted.actionPerformed(URLImage.java:233)   在com.codename1.ui.URLImage $ 4.onSucess(URLImage.java:301)at   com.codename1.ui.URLImage $ 4.onSucess(URLImage.java:297)at   com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53)   在com.codename1.ui.Display.processSerialCalls(Display.java:1154)at   com.codename1.ui.Display.edtLoopImpl(Display.java:1098)at   com.codename1.ui.Display.mainEDTLoop(Display.java:999)at   com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)at at   com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)

此外,在.cn1目录中一览显示URLImage存储文件名,后缀为" ImageURLTMP"当一切都没有NPE时,它就不会出现。

最后,如果我稍后回到这个表单,一切都按预期工作(图像显示,没有NPE)。我试图在imageAdapter中测试downloadedImage nullness,但EncodedImage不为null。

如何避免这种NPE?

2017年3月1日编辑

根据@Diamond和@Shai的回答,我相信NPE的出现是因为InfiniteScrollAdapter想要用行填充屏幕,因此同时启动同一图像的下载(因为它不在缓存中)。因此,解决方案可能是阻止InfiniteScrollAdapter循环(因此它变得有限)。我怎样才能做到这一点 ?

请注意,没有404错误,网络监视器显示响应代码200,如下所示。但是,图像不应该下载3次,是吗?

No 404

2 个答案:

答案 0 :(得分:1)

在适配器中检查downloadedImage.getData()是否为null。我认为它不是,它是一个404错误页面或类似的东西。

在这种情况下,你的适配器可以捕获异常并返回一个与你没有图像存在时预期相符的回退。

这是第二次,因为系统看到tmp文件并假定正在进行下载,因此它不会再次调用下载代码。稍后将tmp文件重命名为最终可下载文件。

答案 1 :(得分:1)

将ImageAdapter更改为以下内容:

(cos(b)-1)

无需检查b

确保您的public static final URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() { @Override public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) { Image tmp = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight()); if (tmp.getWidth() > placeholderImage.getWidth()) { int diff = tmp.getWidth() - placeholderImage.getWidth(); int x = diff / 2; tmp = tmp.subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true); } else if (tmp.getHeight() > placeholderImage.getHeight()) { int diff = tmp.getHeight() - placeholderImage.getHeight(); int y = diff / 2; tmp = tmp.subImage(0, y, Math.min(placeholderImage.getWidth(), tmp.getWidth()), Math.min(placeholderImage.getHeight(), tmp.getHeight()), true); } Image roundMask = Image.createImage(tmp.getWidth(), tmp.getHeight(), 0xff000000); Graphics gr = roundMask.getGraphics(); gr.setColor(0xffffff); gr.fillArc(0, 0, tmp.getWidth(), tmp.getHeight(), 0, 360); Object mask = roundMask.createMask(); tmp = tmp.applyMask(mask); return EncodedImage.createFromImage(tmp, false); } @Override public boolean isAsyncAdapter() { return true; } }; 图片首先应用于您的组件,并在逻辑结束时,使用EDT方法致电tempPlaceholder

URLImage

编辑:

根据@ Shai的回答,您可以检查当前是否正在下载相同的图像并阻止另一个图像被拉出。因为这通常会导致冲突:

callSerially()