关于Picasso加载图片Callback不执行问题

问题背景

代码大致如下,Target或Callback的回调有时候不执行。

https://github.com/square/picasso/issues/352

第一种:使用Target

Picasso.get().load(URL).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.i(TAG, "onBitmapLoaded: " + from);
} @Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
Log.e(TAG, "onBitmapFailed");
} @Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});

第二种:使用Callback

ImageView imageView = new ImageView(this);
Picasso.get().load(URL).into(imageView, new Callback() {
@Override
public void onSuccess() {
Log.i(TAG, "onSuccess: ");
} @Override
public void onError(Exception e) {
Log.e(TAG, "onError" );
}
});

以上代码,通常用在预加载图片的业务中。

问题原因

对于这样偶现的问题,第一反应应该是引用持有问题。果然,上述问题是弱引用问题: WeakReference

源码推导:

// 1.先看into方法:RequestCreator.java
public void into(@NonNull Target target) {
// ...
Action action =
new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
requestKey, tag, errorResId);
picasso.enqueueAndSubmit(action);
} // 2.跟到Action:TargetAction.java
final class TargetAction extends Action<Target> { TargetAction(Picasso picasso, Target target, Request data, int memoryPolicy, int networkPolicy,
Drawable errorDrawable, String key, Object tag, int errorResId) {
// target被传到了super构造器
super(picasso, target, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key, tag,
false);
} @Override
void complete(Bitmap result, Picasso.LoadedFrom from) {
if (result == null) {
throw new AssertionError(
String.format("Attempted to complete action with no result!\n%s", this));
}
Target target = getTarget();
if (target != null) { // 这一句判断很关键
target.onBitmapLoaded(result, from);
if (result.isRecycled()) {
throw new IllegalStateException("Target callback must not recycle bitmap!");
}
}
} @Override
void error(Exception e) {
Target target = getTarget();
if (target != null) { // 这一句判断很关键
if (errorResId != 0) {
target.onBitmapFailed(e, picasso.context.getResources().getDrawable(errorResId));
} else {
target.onBitmapFailed(e, errorDrawable);
}
}
}
} // 3.往上跟到Action的构造方法:Action.java
Action(Picasso picasso, T target, Request request, int memoryPolicy, int networkPolicy,
int errorResId, Drawable errorDrawable, String key, Object tag, boolean noFade) {
// ...
this.target =
target == null ? null : new RequestWeakReference<>(this, target, picasso.referenceQueue);
// ...
}

有此可见,如果this.target这个虚引用,要是在gc的时候被回收了,回调自然也不会有了。

场景复现

以下代码模拟系统内存紧张时候的gc过程,这样偶现问题便成了必现,或极大概率出现。

public void preloadImage() {
Picasso.get().load(URL).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.i(TAG, "onBitmapLoaded: " + from);
} @Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
Log.e(TAG, "onBitmapFailed");
} @Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
}); for (int i = 0; i < 1000; i++) {
double[] b = new double[1000000];
}
System.gc();
}

解决方式

可以考虑通过加持引用,不让若引用销毁。方式有很多种,这里可以考虑用匿名内部类来延长变量的生命周期。

第一种:使用Target

public void preloadImage() {
Log.d(TAG, "preloadImage: preloadImage.");
class Ref {
private Target t;
}
final Ref ref = new Ref();
ref.t = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.i(TAG, "preloadImage.onBitmapLoaded: " + from + ref.hashCode());
} @Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
Log.e(TAG, "preloadImage.onBitmapFailed" + ref.hashCode());
} @Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
} @Override
protected void finalize() throws Throwable {
super.finalize();
Log.e(TAG, "target.finalize!");
}
};
Picasso.get().load(URL).into(ref.t);
}

第二种:使用Callback

public void preloadImage() {
Log.d(TAG, "preloadImage: start.");
final ImageView imageView = new ImageView(this);
Picasso.get().load(URL).into(imageView, new Callback() {
@Override
public void onSuccess() {
Log.i(TAG, "preloadImage.onSuccess: " + imageView.hashCode());
} @Override
public void onError(Exception e) {
Log.e(TAG, "preloadImage.onError" + imageView.hashCode());
} @Override
protected void finalize() throws Throwable {
super.finalize();
Log.e(TAG, "callback.finalize!");
}
});
}

以上。

最新文章

  1. json返回数据时提示字符串超出长度
  2. Qt MainWindow结构
  3. Atitit &#160;&#160;图像处理&#160;平滑&#160;也称&#160;模糊,&#160;归一化块滤波、高斯滤波、中值滤波、双边滤波)
  4. centos安装altas
  5. js高仿QQ消息列表左滑功能
  6. MySQL 函数积累
  7. freeglut第一步
  8. keychain中我的证书与证书, p12与pem, apns, 推送
  9. 【原创】Mac上编译Hadoop1.0.3出现的一些问题
  10. Entity Framework: 视图查询时重复返回第一行值, duplicate frst rows in resultset from a view
  11. 在ubuntu14.04 64位中使用jd-gui
  12. 使用XE5-PACTH破解Delphi-XE5时,出现检查文件大小失败的解决方法
  13. Android_CodeWiki_04
  14. L2-004. 这是二叉搜索树吗?
  15. 关于j2ee工程发布到was上后,部分更新,例修改web.xml配置文件不起作用的原因解析【转】
  16. visual studio 中sstrcpy报错的问题
  17. Android开发之自定义万能BaseAdapter
  18. i3 窗口管理器使 Linux 更美好
  19. KNN分类算法及python代码实现
  20. ubuntu多显示器单触摸屏校准

热门文章

  1. GIL与异步回调
  2. 地图组件demo
  3. SYNPROXY:廉价的抗DoS攻击方案
  4. linux初学者-swap分区篇
  5. 代码审计之metinfo5.1.4
  6. 黑羽压测 做 API接口功能测试
  7. Bellman-Ford 算法
  8. Oracle JDK与OpenJDK到底有什么不同?
  9. chapter02 - 03
  10. GGPLOT2-plotly |让你的火山图“活”过来