Universal Image loader有时无法加载图像

时间:2013-05-17 06:59:43

标签: android universal-image-loader

我正在使用通用图像加载器,我每天都会收到大量无法为用户加载的图像。 我正在使用此代码将错误归结为分析。

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为null。在具有2.1-2.3安卓版本的设备上可以看到此问题,但有一些报告来自较新版本,如4.0.4甚至4.2.2。所以我无法确定导致图像无法加载的原因

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

最常见的错误中有三个是out_of_memory错误...我试图加载的图像不大于1mb,但我需要有ScaleType.Exactly,但是在加载较大的图像时我不会将它们缓存在内存或光盘中,以减少out_of_memory的可能性,但它仍然经常发生。

我的配置:

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

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

更新 正如我在onLoadingFailed上建议的那样更改了代码,我现在看到所有没有.getCause()的报告都是“DECODING_ERROR”,所有这些都是由android 2.2-2.3.6版本报告的,没有更新的。然而,仍有很大一部分用户使用较旧的机器人,任何想法如何减少这个decode_error?我在较旧的机器人上检查了应用程序,图像大部分时间都会加载,但DECODING_ERROR最常报告在分析上。其次,最常见的原因仍然是IO_ERROR java.io.EOFException

更新2

自定义下载器作为nostra建议,将threadPoolSize减少到3设置一个额外的加载 - 如果加载失败尝试再次加载一次然后放弃。我看到加载失败减少了约30%。但仍然会发生 - 500个日常活跃用户在3天内发生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 个答案:

答案 0 :(得分:5)

failReason.getType()不能nullfailReason.getCause()可以。你应该检查它以防止NPE。

如果您通过failReason.getCause()拒绝网络或发生解码错误,则

null可以是ImageLoader.denyNetworkDownloads(true)。这是因为Android无法通过某种原因解码图像。

BTW我建议您使用.cacheOnDisc()即使是大图片(options2)。 也许尝试其他内存缓存实现?例如。 LruMemoryCache

我不知道java.io.EOFException的原因,但您能否检测到那个时间使用的网络?手机还是WiFi?也许尝试使用ImageLoader.handleSlowNetwork(boolean)在网络类型之间切换。

UPD:还尝试减少线程池大小。也许它有助于防止解码错误。 UPD2:网站重定向到网页可能导致解码错误。您可以尝试扩展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;
    }
}

答案 1 :(得分:4)

我从未使用过Universal Image Loader,但在过去的几周内发布了几个非常好的替代品,它们可能值得一看。

第一个是Volley,谷歌在2013年I / O上宣布的新网络库 https://developers.google.com/events/io/sessions/325304728

第二个是Square的毕加索。 Square团队用他们的Android库做了一些非常好的工作。 http://corner.squareup.com/2013/05/picasso-one-dot-oh.html