Picasso加载网络图片失败,提示decodestream时返回null
最近遇到一个问题,项目用的图片加载框架是Picasso,网络加载框架是okhttp,项目在加载轮播图时有时可以正常加载,有时,会加载失败,提示decodestream时返回null。
首先,需要确定是哪个环节出了问题。
网上搜了很多关于“decodestream时返回null”的问题,都说需要在decodestream之前reset stream。不过,由于用的是Picasso,不太方便改代码,再换个思路看一下。
要确认是否是Picasso的问题,那我就用其他图片加载框架替换Picasso,这里,我使用Glide替换Picasso。
替换之后,运行程序,图片加载没有任何问题。
由此,可以确认,问题出在Picasso身上。
于是,我又在网上搜索关于Picasso的这类问题,在百度上,完全没有类似问题,google上倒是可以找到几个类似问题,百度在这方面还需要加油啊。。。
google上搜到的都是GitHub上Picasso使用者提的issue,这里也是说是decodestream调用两次的问题。
于是我查看源码:
static Bitmap decodeStream(InputStream stream, Request request) throws IOException { MarkableInputStream markStream = new MarkableInputStream(stream); stream = markStream; long mark = markStream.savePosition(65536); // TODO fix this crap. final BitmapFactory.Options options = RequestHandler.createBitmapOptions(request); final boolean calculateSize = RequestHandler.requiresInSampleSize(options); boolean isWebPFile = Utils.isWebPFile(stream); markStream.reset(mark); // When decode WebP network stream, BitmapFactory throw JNI Exception and make app crash. // Decode byte array instead if (isWebPFile) { byte[] bytes = Utils.toByteArray(stream); if (calculateSize) { BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options, request); } return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); } else { if (calculateSize) { BitmapFactory.decodeStream(stream, null, options); RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options, request); markStream.reset(mark); } Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options); if (bitmap == null) { // Treat null as an IO exception, we will eventually retry. throw new IOException("Failed to decode stream."); } return bitmap; } }
并定位到这个地方,进行单步调试,发现decodestream确实调用了两次,但是,jack已经进行了reset操作。这个地方不应该会出现问题。
继续找资料,在Github找到一个解决方案:在url后面加上“?”+System.currentTimeMillis()。
经测试,这样做可以正确加载图片。
为什么url后加时间戳就能成功呢?
url加时间戳后每次都从网络下载图片,没加的话会从缓存中加载图片。
据此,我有理由怀疑,是缓存问题,导致这个问题出现。
我在原有代码的基础上(url后面不加“?”+时间戳)加上
.memoryPolicy(MemoryPolicy.NO_CACHE)
.networkPolicy(NetworkPolicy.NO_CACHE)
再次调试,发现可以正常加载图片。
由此可以确定:是缓存问题导致加载图片失败。
嗯,接下去该自定义缓存试一下了。
再次到网上搜索资料(爱分享的程序员/媛就是这么招人喜欢)
参考http://www.jianshu.com/p/6241950f9daf写了个自定义缓存。
贴几处关键代码:
OkHttpClient client = new OkHttpClient .Builder() .cache(new Cache(BaseApplication.getContext().getCacheDir(), 1000 * 1024)) .addInterceptor(new CaheInterceptor(BaseApplication.getContext())) .addNetworkInterceptor(new CaheInterceptor(BaseApplication.getContext())) .build(); mPicasso = new Picasso.Builder(BaseApplication.getContext()) .downloader(new ImageDownLoader(client)) .build(); mPicasso.with(BaseApplication.getContext()).setIndicatorsEnabled(true);//左上角标出颜色,红色为从网络获取,绿色为从内存中获取,蓝色为从硬盘中获取