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

Java 模拟器中InfiniteSrollAdapter中的URLImage显示NPE(CodenameOne),java,codenameone,Java,Codenameone,我的应用程序有一个InfiniteScrollAdapter,通过URLImage和URLImage.ImageAdapter填充图像 在模拟器(Iphone3GS或Xoom或GoogleNexus7)中,NPE在第一次出现InfiniteSrollAdapter时显示,尽管服务器上确实存在该文件 请注意:在这个测试中,数据库中只有一个条目。因此,在下面的图像上,您应该看到同一行(图像+文本)重复了3次。 请注意,未显示图标中的顺序可能不同 我用来下载图像的代码是: Image tempPl

我的应用程序有一个
InfiniteScrollAdapter
,通过
URLImage
URLImage.ImageAdapter
填充图像

在模拟器(Iphone3GS或Xoom或GoogleNexus7)中,NPE在第一次出现
InfiniteSrollAdapter
时显示,尽管服务器上确实存在该文件

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

请注意,未显示图标中的顺序可能不同

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

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];

    } 
在stacktrace中,NPE似乎来自被覆盖的
URLImage.ImageAdapter

java.lang.IllegalArgumentException:为给定的 长度为0的图像数据 com.codename1.ui.Image.createImage(Image.java:654)位于 com.codename1.ui.EncodedImage.getInternal(EncodedImage.java:365)位于 com.codename1.ui.EncodedImage.getInternalImpl(EncodedImage.java:340) 位于com.codename1.ui.EncodedImage.getHeight(EncodedImage.java:522) com.codename1.ui.Image.scaledLargerRatio(Image.java:899)位于 ParametresGeneraux$1.lambda$adaptImage$0(ParametresGeneraux.java:564) 位于com.codename1.ui.runnablerrapper.run(runnablerrapper.java:95) com.codename1.ui.Display.processSerialCalls(Display.java:1154)位于 com.codename1.ui.Display.edtlopimpl(Display.java:1098)位于 com.codename1.ui.Display.invokeAndBlock(Display.java:1207)位于 com.codename1.ui.Display.invokeAndBlock(Display.java:1244)位于 com.codename1.ui.URLImage$DownloadCompleted.actionPerformed(URLImage.java:233) 在com.codename1.ui.URLImage$4.onsuces(URLImage.java:301)上 com.codename1.ui.URLImage$4.onsuces(URLImage.java:297)位于 com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53) 在com.codename1.ui.Display.processSerialCalls(Display.java:1154)中 com.codename1.ui.Display.edtlopimpl(Display.java:1098)位于 com.codename1.ui.Display.mainedCloop(Display.java:999)位于 com.codename1.ui.runnablerrapper.run(runnablerrapper.java:120)位于 com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176) [EDT]0:0:0,1-代号1修订版: e5c43877074c18b4b5c7748d000e5cfac75ab749 2318

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

此外,只要浏览一下.cn1目录,就会看到带有后缀“ImageURLTMP”的URLMAGE存储文件名,在没有NPE的情况下,该后缀不会出现

最后,如果我稍后再回到这个表单,一切都按预期进行(显示了图像,没有NPE)。我试图在
imageAdapter
中测试下载的图像是否为空,但EncodedImage不为空

我如何避免这种NPE

编辑2017年3月1日

根据@Diamond和@Shai的回答,我认为NPE的出现是因为InfiniteSrollAdapter希望用行填充屏幕,并因此同时启动相同映像的下载(因为它不在缓存中)。因此,一个解决方案可以是防止InfiniteSrollAdapter循环(因此它变成有限的)。我该怎么做

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


在适配器中检查
下载的image.getData()
是否为
null
。我想不是,是404错误页面或类似的东西

在这种情况下,适配器可以捕获异常并返回一个回退,该回退与不存在映像时所期望看到的内容相匹配


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

将ImageAdapter更改为以下内容:

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
图像应用于组件,并在逻辑结束时,在
callSerially()方法中调用
URLImage

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);

myComponent.setIcon(tempPlaceholder);


...


//Then call this at the end of everything
Display.getInstance().callSerially(() -> {
    EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);

    final Image reportImage = URLImage.createToStorage(
                        roundPlaceholder,
                        photoFilenameInStorage,
                        currentReport.getPhotoPath(),
                        ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
                );
    myComponent.setIcon(reportImage);
    myComponent.getComponentForm().repaint();
});
编辑: 根据@Shai的回答,您可以检查您当前是否处于停机状态
//Declare this at the top of your class
final static private Map<String, Image> LOADED_URLS = new HashMap<>(); 

//Then change the URLImage image method to this
Display.getInstance().callSerially(() -> {
    EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);

    final Image reportImage = LOADED_URLS.containsKey(photoFilenameInStorage) ? LOADED_URLS.get(photoFilenameInStorage)
                        : URLImage.createToStorage(
                        roundPlaceholder,
                        photoFilenameInStorage,
                        currentReport.getPhotoPath(),
                        ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
                );
    LOADED_URLS.put(photoFilenameInStorage, reportImage);
    myComponent.setIcon(reportImage);
    myComponent.getComponentForm().repaint();
});