通用图片加载器有时无法加载图片

10

我正在使用通用图片加载器,每天用户遇到的无法加载的图片数量相当大。 我正在使用以下代码将错误信息发送到分析系统。

public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
  try
  {
    String fail = failReason.getType().toString();
    String fail4 = failReason.getCause().toString();
    String sum = fail + " " + fail4;
    EasyTracker.getTracker().sendException(sum, false);
  }
  catch (Exception e)
  {
    EasyTracker.getTracker().sendException(e.getMessage(), false);
  }
}

大多数情况下,它会捕获异常(例如getType或getCause为空)。此问题在2.1-2.3 Android版本的设备上出现,但也有一些来自较新版本(如4.0.4甚至4.2.2)的报告。所以我不能确定导致图像加载失败的原因。

另一个问题是IO_ERROR java.io.EOFException,这在较新的Android版本上经常出现。

前三个最常见的错误是内存不足错误... 我尝试加载的图像大小不超过1MB,但我需要使用ScaleType.Exactly,而在加载更大的图像时,我没有将它们缓存在内存或磁盘中,以减少内存不足的可能性,但仍然经常发生。

我的配置:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(xxx.getApplicationContext())
.threadPoolSize(4)
.memoryCache(new WeakMemoryCache())
.imageDownloader(new BaseImageDownloader(xxx.getApplicationContext(),10 * 1000, 30 * 1000)) 
.build();

if(!ImageLoader.getInstance().isInited())
            ImageLoader.getInstance().init(config);

// options is used for images smaller in size (5kb-150kb)
options = new DisplayImageOptions.Builder()
.cacheInMemory()
.cacheOnDisc()
.showStubImage(R.drawable.stub)
.showImageOnFail(R.drawable.failed)
.imageScaleType(ImageScaleType.EXACTLY)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();

// options2 is used for images big in size (300kb-1,2mb)
options2 = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.stub)
.showImageOnFail(R.drawable.failed)
.imageScaleType(ImageScaleType.NONE) // NONE because I need to have full size bitmap loaded
.bitmapConfig(Bitmap.Config.RGB_565)
.build();

有人能告诉我如何优化我的图像加载,以减少加载失败的图片吗?因为我觉得这些不断的加载失败会让我失去一些用户。

更新 按照nostra在onLoadingFailed中建议的更改代码后,我现在看到所有没有.getCause()的报告都是“DECODING_ERROR”,而且所有这些报告都是由android 2.2-2.3.6版本报告的,没有来自更新版本。然而,我的大部分用户仍在使用旧版android,有什么办法可以减少这种解码错误吗?我在旧版android上亲自检查了应用程序,图片大多数情况下确实加载了,但在分析报告中最常见的仍然是IO_ERROR java.io.EOFException

更新2

按照nostra的建议,定制了下载器,将线程池大小减小到3,设置了额外的加载-如果加载失败,请再尝试加载一次,然后放弃。我看到加载失败的情况减少了约30%。但仍然存在-每天500个活跃用户中有100个解码错误(仅限于2.2-2.3.6版本),160个EOF错误(4.0及以上)。

更新3

最新更新的版本解决了很多解码错误和EOFExceptions,我认为主要是因为我在第一次加载失败后尝试重新加载相同的图像。不过...现在我面临另一个问题:设备上没有剩余空间java.io.IOException: write failed: ENOSPC (No space left on device)。我正在使用LimitedDiscCache。

2个回答

5

failReason.getType() 不能为 null,但 failReason.getCause() 可以为 null。您应该检查它以防止 NPE。

如果通过 ImageLoader.denyNetworkDownloads(true) 拒绝网络或发生解码错误,则 failReason.getCause() 可以为 null。这是因为 Android 由于某种原因无法解码图像。

顺便说一下,我建议您即使对于大图片(options2),也使用.cacheOnDisc()。还可以尝试其他内存缓存实现吗?例如LruMemoryCache

我不知道java.io.EOFException的原因,但您能否检测在那个时候使用了哪个网络?移动网络还是 WiFi?也许可以尝试使用ImageLoader.handleSlowNetwork(boolean)在网络类型之间进行切换。

更新: 同样尝试减少线程池大小。 也许可以帮助防止解码错误。 更新2: 解码错误可能是由于网站重定向到网页引起的。您可以尝试扩展BaseImageDownloader并在请求中添加空字符串以获取“User-Agent”标头。

public class MyImageDownloader extends BaseImageDownloader {

private static final int MAX_REDIRECT_COUNT = 5;

public MyImageDownloader(Context context) {
    super(context);
}

protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
    HttpURLConnection conn = connectTo(imageUri);

    int redirectCount = 0;
    while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
        conn = connectTo(conn.getHeaderField("Location"));
        redirectCount++;
    }

    return new BufferedInputStream(conn.getInputStream(), BUFFER_SIZE);
}

protected HttpURLConnection connectTo(String url) throws IOException {
    String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS);
    HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection();
    conn.setConnectTimeout(connectTimeout);
    conn.setReadTimeout(readTimeout);
    conn.setRequestProperty("User-Agent", "");
    return conn;
}
}

自 UIL 1.8.5 版本以后:

public class MyImageDownloader extends BaseImageDownloader {
    @Override
    protected HttpURLConnection createConnection(String url) throws IOException {
        HttpURLConnection conn = super.createConnection(url);
        conn.setRequestProperty("User-Agent", "");
        return conn;
    }
}

也许我根本不应该使用cacheInMemory,以减少内存不足的可能性?我正在尽力在服务器端缩小图像大小(压缩和显示缩略图像),但是我仍然会在分析报告中收到内存不足的消息。我自己无法重现任何这些错误。除了EOFException之外,当我尝试快速滑动已缓存的图像时,它很少发生,并且其中一些无法加载并出现EOFException。至于互联网连接,我无法确定,但我的大多数用户都不在wifi上,所以他们可能有较慢的连接。 - Datenshi
也尝试减少线程池大小。或许有助于防止解码错误。 - nostra13
更新的答案。UPD2以防止解码错误。 - nostra13
1
谢谢您没有忘记这个问题,我会在最近的更新中添加您的修复,并发布结果。 - Datenshi
我已经更新了我的问题并附上了结果。如果你还有任何想法可以尝试,请分享给我 :) - Datenshi
@NOSTRA,非常感谢!!我花了几天时间才发现这是重定向问题。但我不太明白它是如何解决重定向问题的。 - Chen Xiaofeng

4

谢谢,我会看一下这些的。但问题仍然是关于通用图像加载器:) - Datenshi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接