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