关于Picasso加载图片Callback不执行问题
关于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!");
}
});
}
以上。
关于Picasso加载图片Callback不执行问题的更多相关文章
- Picasso 加载图片到RelativeLayout之解决方案
Picasso 加载图片到ImageView 或者自己的自定义View都是可以直接调用对应API的,但是用into(0直接也加载到RelatieLayout就不好使了,可以这样来: Picasso.w ...
- (Android图片内存优化)Picasso加载图片 教程。。详细版
Picasso 是 Android 上一个强大的图片下载和缓存库. 示例代码: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Picasso.with( ...
- 实例演示Android异步加载图片
本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...
- 实例演示Android异步加载图片(转)
本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...
- jquery的promise实践--连续加载图片
在javascript设计模式实践之代理模式--图片预加载中用代理模式实现了图片预加载功能. 现在就更进一步,完成一个能够一张一张的连续图片加载的功能. 功能: 1.一张一张加载图片. 2.加载错误, ...
- android 加载图片框架--Glide使用详解
一.简介 Glide,一个被google所推荐的图片加载库,作者是bumptech.这个库被广泛运用在google的开源项目中,包括2014年的google I/O大会上发布的官方app.(PS:众所 ...
- JQuery实现无刷新下拉加载图片
最近做的一个项目需要做页面无刷新下拉加载图片,调研了一番,大多都采用检测滚动条达到底部,然后利用ajax加载下一页数据对页面数据进行添加,根据这一逻辑,自己写了一个,具体代码如下: JQu ...
- android 网络加载图片,对图片资源进行优化,并且实现内存双缓存 + 磁盘缓存
经常会用到 网络文件 比如查看大图片数据 资源优化的问题,当然用开源的项目 Android-Universal-Image-Loader 或者 ignition 都是个很好的选择. 在这里把原来 ...
- ListView异步加载图片,完美实现图文混排
昨天参加一个面试,面试官让当场写一个类似于新闻列表的页面,文本数据和图片都从网络上获取,想起我还没写过ListView异步加载图片并实现图文混排效果的文章,so,今天就来写一下,介绍一下经验. Lis ...
随机推荐
- SQLyog12最新版破解
1.SQLyog-12.2.4-0.x64Trial.exe,直接去官网下载. 2.修改注册表项 开始-运行-regedit ,进入注册表 HKEY_CURRENT_USER\Software\ ...
- Linux设备驱动程序学习----1.设备驱动程序简介
设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介 Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...
- PointCloud及其经典论文介绍
这篇博客会介绍点云的基本知识,重点介绍最近两年发表的部分经典论文,有什么建议欢迎留言! 点云基本介绍 点云是某个坐标系下的点的数据集,包含了丰富的信息,可以是三维坐标X,Y,Z.颜色.强度值.时间等等 ...
- bean的创建(五)第三部分 bean工厂方法参数的解析
准备好一系列参数之后,开始参数类型的转换,方法参数的对应. ConstructorResolver.createArgumentArray private ArgumentsHolder create ...
- Nginx搭建详细
Linux 安装Nginx搭建详细内容 进入:/usr/java/nginx位置下载nginx: wget et http://nginx.org/download/nginx-1.8.0.tar.g ...
- .NET Core on K8S学习实践系列文章索引(Draft版)
一.关于这个系列 自从去年(2018年)底离开工作了3年的M公司加入X公司之后,开始了ASP.NET Core的实践,包括微服务架构与容器化等等.我们的实践是渐进的,当我们的微服务数量到了一定值时,发 ...
- codeforces 339A.Helpful Maths B.Xenia and Ringroad 两水题
A.题意就是把字符串里面的数字按增序排列,直接上代码. #include <string.h> #include <stdio.h> #include <algorith ...
- ES 24 - 如何通过Elasticsearch进行聚合检索 (分组统计)
目录 1 普通聚合分析 1.1 直接聚合统计 1.2 先检索, 再聚合 1.3 扩展: fielddata和keyword的聚合比较 2 嵌套聚合 2.1 先分组, 再聚合统计 2.2 先分组, 再统 ...
- Intent 使用详解
极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android Intent 是一个消息传递对象,主要用于组建之间的通讯,例如:启动Activit ...
- DesignPattern系列__06迪米特原则
迪米特原则定义 迪米特原则,也叫最少知道原则,即一个类应该对自己依赖的类知道的越少越好,而你被依赖的类多么复杂,对我都没有关系.也就是说,对于别依赖的类来说,不管业务逻辑多么复杂,都应该尽量封装在类的 ...