Glide
一个重要的特点就是通过一个透明的Fragment
来感知外层Activity
或Fragment
的生命周期,在onStart
方法里面启动网络请求,onStop
里面暂停请求,onDestroy
里面解除监听并释放内存。那么,
Glide
是怎么做到这个监听事件的?
用于监听的接口
Glide
里面用于监听生命周期的接口总有两个,它们分别是 LifecycleListener
和 Lifecycle
:
/**
* 一个用来监听Fragment或Activity生命周期的回调接口
*/
public interface LifecycleListener {
/**
* Fragment或Activity生命周期为onStart时的回调
*/
void onStart();
/**
* Fragment或Activity生命周期为onStop时的回调
*/
void onStop();
/**
* Fragment或Activity生命周期为onDestroy时的回调
*/
void onDestroy();
}
LifecycleListener
是用于回调的接口,那么 Lifecycle
呢:
/**
* 用于监听Activity / Fragment生命周期事件的接口。
*/
public interface Lifecycle {
/**
* 添加生命周期方法的回调监听
*/
void addListener(@NonNull LifecycleListener listener);
/**
* 移除生命周期方法的回调监听
*/
void removeListener(@NonNull LifecycleListener listener);
}
Lifecycle
就是用来注册 LifecycleListener
的。他们的具体关联关系,可以看一下 ActivityFragmentLifecycle
,这个类是 Lifecycle
实现类:
public class ActivityFragmentLifecycle implements Lifecycle {
/**
* 弱引用WeakHashMap持有LifecycleListener(key)再转为Set
* Set底层就是用Map来实现的,只保留key
*/
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
/**
* 是否start了
*/
private boolean isStarted;
/**
* 是否Destroyed了
*/
private boolean isDestroyed;
void onStart() {
isStarted = true;
//由于是弱引用Map,循环需要过滤空的item
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
//由于是弱引用Map,循环需要过滤空的item
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
//由于是弱引用Map,循环需要过滤空的item
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
/**
* 添加监听并依据当前获取的生命周期状态来设置方法回调
*
* @param listener 用来监听Fragment或Activity生命周期的回调接口
*/
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
return;
}
if (isStarted) {
listener.onStart();
return;
}
listener.onStop();
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
}
上面有用到一个 Util.getSnapshot
的静态方法,它就是一个过滤操作,把集合中的空数据对象给过滤了,毕竟这里是弱引用持有:
/**
* 复制并移除集合中的空数据,提供安全可靠的集合
*
* @return 一个没有空数据对象的集合
*/
@NonNull
public static <T> List<T> getSnapshot(@NonNull Collection<T> other) {
List<T> result = new ArrayList<>(other.size());
for (T item : other) {
if (item != null) {
result.add(item);
}
}
return result;
}
这样子一来前期准备就做好了,现在就缺一个除了感知外层生命周期就没有其他作用的 Fragment
了。
感知外层生命周期的 Fragment
在 Glide
里面,用来感知外层生命周期的 Fragment
总共有两个,是不是有点意外。但是 Glide
作为一个开源的 SDK 总要考虑到各种兼容的情况,而 Fragment
是分两个版本的,一个是 support v4 的兼容版本,一个则是系统原生版本,后者只支持 Android 3.0 以上。
这里我就只介绍 support v4 的 SupportRequestManagerFragment
,不过这两个 Fragment
里面的代码其实都是一样的:
public class SupportRequestManagerFragment extends Fragment {
private static final String TAG = "SupportRMFragment";
private final ActivityFragmentLifecycle mLifecycle;
private RequestManager requestManager;
//.....
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
}
整个类的代码里面就没有找到 onCreateView
,因此这个 Fragment
是没有任何 UI 界面的,也就是隐形的。
监听生命周期的核心代码就上面这些,是不是还漏了什么呢?是的,这里就只看到了回调事件,那么是在哪里去添加监听的呢?
控制监听的 RequestManager
之前只说了 Lifecycle
的实现类,现在来看下 LifecycleListener
的实现类,也就是上面代码的 RequestManager
对象:
/**
* 这个是Glide用于管理网络请求的类
* 智能控制Glide网络请求的停止、启动和再次启动
*/
public class RequestManager implements LifecycleListener{
//用于添加和移除监听的Lifecycle对象
final Lifecycle lifecycle;
/**
* 伪构建方法,这里省略了其他参数和代码
*/
RequestManager(Lifecycle lifecycle){
//添加监听
lifecycle.addListener(this);
}
@Override
public void onStart() {
//省略部分代码...
}
@Override
public void onStop() {
//省略部分代码...
}
@Override
public void onDestroy() {
//省略部分代码...
//移除监听
lifecycle.removeListener(this);
}
}
这里直接在 RequestManager
的构造方法里面完成了生命周期监听的绑定,从而依据感知外层生命周期的 SupportRequestManagerFragment
启动网络请求、停止网络请求、再启动网络请求和最后的销毁工作,在 onDestroy
方法里面来移除监听,防止了内存泄露。
总结
就这么一套东西看下来,其实都很好懂,关键是需要培训自己养成这种代码的思维,与君共勉。