【发布时间】:2017-07-18 22:56:04
【问题描述】:
我的应用程序具有一个 InfiniteScrollAdapter,其中包含通过 URLImage 和 URLImage.ImageAdapter 填充的图像。
在模拟器(Iphone3GS 或 Xoom 或 GoogleNexus7)中,NPE 会在第一次出现 InfiniteScrollAdapter 时显示,尽管该文件确实存在于服务器上。
请注意:在此测试中,数据库中只有一个条目。所以在下图中你应该看到的是同一行(图像 + 文本)重复了 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];
}
在堆栈跟踪中,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) 在 com.my.application.ParametsGeneaux$1.lambda$adaptImage$0(ParametsGeneraux.java:564) 在 com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:95) 在 com.codename1.ui.Display.processSerialCalls(Display.java:1154) 在 com.codename1.ui.Display.edtLoopImpl(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.onSucess(URLImage.java:301) 在 com.codename1.ui.URLImage$4.onSucess(URLImage.java:297) 在 com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53) 在 com.codename1.ui.Display.processSerialCalls(Display.java:1154) 在 com.codename1.ui.Display.edtLoopImpl(Display.java:1098) 在 com.codename1.ui.Display.mainEDTLoop(Display.java:999) 在 com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120) 在 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 在 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) 在 com.my.application.ParametsGeneaux$1.lambda$adaptImage$0(ParametsGeneraux.java:564) 在 com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:95) 在 com.codename1.ui.Display.processSerialCalls(Display.java:1154) 在 com.codename1.ui.Display.edtLoopImpl(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.onSucess(URLImage.java:301) 在 com.codename1.ui.URLImage$4.onSucess(URLImage.java:297) 在 com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53) 在 com.codename1.ui.Display.processSerialCalls(Display.java:1154) 在 com.codename1.ui.Display.edtLoopImpl(Display.java:1098) 在 com.codename1.ui.Display.mainEDTLoop(Display.java:999) 在 com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120) 在 com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
另外,扫一眼.cn1目录,可以看到后缀为“ImageURLTMP”的URLImage存储文件名,在没有NPE的情况下不会出现。
最后,如果我稍后返回此表单,一切都会按预期工作(显示图像,没有 NPE)。我尝试在 imageAdapter 中测试下载的图像是否为空,但 EncodedImage 不为空。
如何避免这种 NPE?
2017 年 3 月 1 日编辑
根据@Diamond 和@Shai 的回答,我相信NPE 的发生是因为InfiniteScrollAdapter 想要用行填充屏幕并因此同时启动同一图像的下载(因为它不在缓存中)。因此,一种解决方案可能是防止 InfiniteScrollAdapter 循环(因此它变得有限)。我怎样才能做到这一点 ?
另请注意,没有 404 错误,网络监视器显示响应代码 200,如下图所示。但是图像不应该被下载 3 次,不是吗?
【问题讨论】:
-
发布您用于 InfinteScroller 和 URLImage 的代码的 sn-p
-
我忘了!查看我的编辑@Diamond!
标签: java codenameone