Glide是比较常用的图片加载库,因为我在项目里使用到了,所以会跟EventBus一样参考网上前辈的文章做一个学习笔记。
开源库的比较
图片加载是 Android 项目中必备的需求,而图片加载的开源库也有很多:有 UniversalImageLoader、Picasso、Fresco、Glide等。
- UniversalImageLoader是老牌的图片加载库(我在最初的两个项目里使用的都是它)。但是作者已经不再维护项目了,所以 UniversalImageLoader不推荐在项目中使用了。
- Picasso 是图片开源库,是Glide的基础。
- Glide 是基于 Picasso 的,做了大量优化与改进。Glide 默认的 Bitmap 格式是 RGB_565 格式,而 Picasso 默认的是 ARGB_8888 格式,这个内存开销要小一半。在磁盘缓存方面,Picasso 只会缓存原始尺寸的图片,而 Glide 缓存的是多种规格。最重要的一个特性是 Glide 支持加载 Gif 动态图,而 Picasso 不支持该特性。总体来说,Glide 是在 Picasso 基础之上进行的二次开发,各个方面做了不少改进,不过这也导致他的包比 Picasso 大不少。
- Fresco 是新一代的图片加载库, Android 应用程序可用的内存有限,经常会因为图片加载导致 OOM。而 Fresco就在更底层的 Native 堆处理图片。于是 Fresco 将图片放到一个特别的内存区域叫 Ashmem 区,就是属于 Native 堆,图片将不再占用 App 的内存,Java 层对此无能为力,这里是属于 C++ 的地盘,所以能大大的减少 OOM。所以此库包也比较大,底层涉及到的 C++ 领域。
- 大部分情况 Glide 都能满足需求,但是如果 App 中大量使用图片,那么用 Fresco是更好的选择。
设计图
引用自Glide 源码解析
流程图
引用自Glide 源码解析
使用与简介
Glide.with(imageView.getContext())
.load(url)
.placeholder(defaultImage)
.error(failImage)
.into(imageView);
如上,Glide 库使用流接口(fluent interface)。流接口(fluent Interface)是指实现一种实现面向对象的能提高代码可读性的API的方法。Glide可以从资源,文件目录和网络上加载图片资源。当加载图片时,Glide 使用3个来源:内存,磁盘和网络(从最快到最慢排序)。Glide 建造者要求最少有三个参数:
with(Context context) ;load(String imageUrl) - 这里你可以指定哪个图片应该被加载,同上它会是一个字符串的形式表示一个网络图片的 URL;into(ImageView targetImageView) 你的图片会显示到对应的 ImageView 中。
Glide.with方法
如上一段的代码可以看出,调用了Glide类的with方法(例子里使用的是第一个)。
////获取RequestManager对象,该类实现了LifeCycleListener接口,绑定Activity/Fragment生命周期,对请求进行暂停,恢复,清除操作。
public static RequestManager with(Context context) {
//获取RequestManager对象
//得到RequestManagerRetriever实例,该类将RequestManager和自定义Fragment(如RequestManagerFragment,SupportRequestManagerFragment)绑定,从而实现在生命周期管理回调。这里自定义Fragment值得注意。
RequestManagerRetriever retriever = RequestManagerRetriever.get();//新建一个handler,handler = new Handler(Looper.getMainLooper(), this /* Callback */);RequestManagerRetriever实现了Handler.Callback。
return retriever.get(context);
}
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(FragmentActivity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
可以看出,5个函数都是起先调用了RequestManagerRetriever retriever = RequestManagerRetriever.get()。他们最后都创建了RequestManager对象。
RequestManagerRetriever
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
//判断是不是主线程,并且context不是Application的实例
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
在这里,特别提到ContextWrapper,它与context的关系如下图:
如果我调用了Glide.with(imageView.getContext())的话,那么应该调用return get((FragmentActivity) context);步骤。
public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
//判断是否在主线程
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);//判断界面是否已经销毁了
FragmentManager fm = activity.getSupportFragmentManager();//获取FragmentManager 对象(android.support.v4.app包带的)
return supportFragmentGet(activity, fm);//创建Fragment,RequestManager并将其绑定
}
}
RequestManager/supportFragmentGet
RequestManager supportFragmentGet(Context context, FragmentManager fm) {
//获取RequestManagerFragment,主要利用Frament进行请求生命周期管理
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
//requestManager 为空,即首次加载初始化requestManager ,并调用setRequestManager设置到RequestManagerFragment
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);//复用
}
return requestManager;
}
SupportRequestManagerFragment 是一个无界面的Fragment类,起到把请求和Activity生命周期同步的作用。上面代码主要的部分就是getSupportRequestManagerFragment函数,获取到了一个fragment。
getSupportRequestManagerFragment
RequestManagerFragment getRequestManagerFragment(FragmentManager fm) {
RequestManagerFragment current = (RequestManagerFragment)fm.findFragmentByTag("com.bumptech.glide.manager");//强转,看看有没有以当前tag命名的fragment,不为空的话直接返回,为空的话需要创建。
if(current == null) {
current = (RequestManagerFragment)this.pendingRequestManagerFragments.get(fm);//pendingRequestManagerFragments是一个hashmap,创建的RequestManagerFragment 对象会存放在其中,复用。
if(current == null) {
current = new RequestManagerFragment();
this.pendingRequestManagerFragments.put(fm, current);//存放在hashmap里。
fm.beginTransaction().add(current, "com.bumptech.glide.manager").commitAllowingStateLoss();
this.handler.obtainMessage(1, fm).sendToTarget();//发送消息,同时会把hashmap中的fragment移除(代码不贴了)
}
}
return current;
}
上面的代码中,创建RequestManagerFragment是比较关键的一步。
com.bumptech.glide.manager/RequestManagerFragment
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
private final RequestManagerTreeNode requestManagerTreeNode;
private RequestManager requestManager;
private final HashSet<RequestManagerFragment> childRequestManagerFragments;
private RequestManagerFragment rootRequestManagerFragment;
public RequestManag