Android开发中经常使用Glide来加载图片,一般得使用如下
Glide.with(this).load("http://abc.com/1.png").into(imageView);
Glide就会完成图片得下载,缓存,缩放,显示等流程。其中应用进入后台,图片会暂停加载得策略,所以就看下Glide是如何实现生命周期得管理得。
先看下Glide.with(this)得源码实现,由于传入得实参一般都是Activity,Fragment,FragmentActivity Context等不同得重载目标方法,所以这里看下FragmentActivity。
/**
* Begin a load with Glide that will tied to the give {@link
* androidx.fragment.app.FragmentActivity}'s lifecycle and that uses the given {@link
* androidx.fragment.app.FragmentActivity}'s default options.
*
* @param activity The activity to use.
* @return A RequestManager for the given FragmentActivity that can be used to start a load.
*/
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
看下getRetriever(activity)得实现
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
Preconditions.checkNotNull(
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
}
首先检查传入得context参数是否为空,当Fragment语页面绑定钱或者绑定后,这些生命周期获得宿主Activity为空。
接着看下get(activity)得源码。
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
//前后台判断
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
//从activity中获取FragmentManager 实例
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
首先判断当前应用是否在前台,如果是运行get(activity.getApplicationContext());,否则获取Activity得FragmentManager 对象,然后传给supportFragmentGet。先看下应用在前台得逻辑。
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
看下getSupportRequestManagerFragment 是逻辑。
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
//判断实例为空,则创建Fragment实例,并保存到pendingSupportRequestManagerFragments.
if (current == null) {
//用FragmentManager获取SupportRequestManagerFragment实例
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
//创建实例
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
//如果Activity可见,回调Fragment得onStart函数
current.getGlideLifecycle().onStart();
}
//保存Fragment
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
从 Activity 的 FragmentManager 中查找是否存在名为 FRAGMENT_TAG 的 Fragment实例。这个实例相当于一个隐形的钩子,挂在 Activity 监听界面生命周期变化。
@VisibleForTesting static final String FRAGMENT_TAG = "com.bumptech.glide.manager";
所以主要是通过获取Fragment实例,绑定在Activity监听界面得生命周期得变化,并回调Glide得图片加载策略.
接着看下SupportRequestManagerFragment得源码。
public class SupportRequestManagerFragment extends Fragment {
private static final String TAG = "SupportRMFragment";
private final ActivityFragmentLifecycle lifecycle;
private final RequestManagerTreeNode requestManagerTreeNode =
new SupportFragmentRequestManagerTreeNode();
private final Set<SupportRequestManagerFragment> childRequestManagerFragments = new HashSet<>();
@Nullable private SupportRequestManagerFragment rootRequestManagerFragment;
@Nullable private RequestManager requestManager;
@Nullable private Fragment parentFragmentHint;
@VisibleForTesting
@SuppressLint("ValidFragment")
public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
@NonNull
ActivityFragmentLifecycle getGlideLifecycle() {
return lifecycle;
}
// 不同生命周期得 lifecycle 回调。
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
registerFragmentWithRoot(getActivity());
} catch (IllegalStateException e) {
// OnAttach can be called after the activity is destroyed, see #497.
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to register fragment with root", e);
}
}
}
@Override
public void onDetach() {
super.onDetach();
parentFragmentHint = null;
unregisterFragmentWithRoot();
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
}
接着看下Lifecycle得实现类ActivityFragmentLifecycle得源码。
/**
* A {@link com.bumptech.glide.manager.Lifecycle} implementation for tracking and notifying
* listeners of {@link android.app.Fragment} and {@link android.app.Activity} lifecycle events.
*/
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
private boolean isStarted;
private boolean isDestroyed;
/**
* Adds the given listener to the list of listeners to be notified on each lifecycle event.
*
* <p>The latest lifecycle event will be called on the given listener synchronously in this
* method. If the activity or fragment is stopped, {@link LifecycleListener#onStop()}} will be
* called, and same for onStart and onDestroy.
*
* <p>Note - {@link com.bumptech.glide.manager.LifecycleListener}s that are added more than once
* will have their lifecycle methods called more than once. It is the caller's responsibility to
* avoid adding listeners multiple times.
*/
//把给定得添加器添加到监听列表,接收生命周期得回调,如果应用已经销毁了,则回调onDestroy,
//onStart和onStop也是类似
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
//取消监听
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
isStarted = true;
//观察者模式,下发生命周期回调
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
实现所有图片加载得任务,创建LifecycleListener 放入 ActivityFragmentLifecycle 中,随后注册所有得监听器,当应用进入到不同得生命周期,实现暂停没开始加载等不同得策略。
LifecycleListener 得实现类是RequestManager,负责请求,加载,取消,完成得功能是TargetTracker实现得,看下TargetTracker得源码。
/**
* A class for tracking, canceling, and restarting in progress, completed, and failed requests.
*
* <p>This class is not thread safe and must be accessed on the main thread.
*/
public class RequestTracker {
private static final String TAG = "RequestTracker";
// Most requests will be for views and will therefore be held strongly (and safely) by the view
// via the tag. However, a user can always pass in a different type of target which may end up not
// being strongly referenced even though the user still would like the request to finish. Weak
// references are therefore only really functional in this context for view targets. Despite the
// side affects, WeakReferences are still essentially required. A user can always make repeated
// requests into targets other than views, or use an activity manager in a fragment pager where
// holding strong references would steadily leak bitmaps and/or views.
private final Set<Request> requests =
Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
// A set of requests that have not completed and are queued to be run again. We use this list to
// maintain hard references to these requests to ensure that they are not garbage collected
// before they start running or while they are paused. See #346.
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final List<Request> pendingRequests = new ArrayList<>();
private boolean isPaused;
/** Starts tracking the given request. */
//开始运行请求
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
@VisibleForTesting
void addRequest(Request request) {
requests.add(request);
}
/**
* Stops tracking the given request, clears, and recycles it, and returns {@code true} if the
* request was removed or invalid or {@code false} if the request was not found.
*/
public boolean clearRemoveAndRecycle(@Nullable Request request) {
// It's safe for us to recycle because this is only called when the user is explicitly clearing
// a Target so we know that there are no remaining references to the Request.
return clearRemoveAndMaybeRecycle(request, /*isSafeToRecycle=*/ true);
}
// 停止请求,并进行清除和回收工作,请求如果是用户主动发起,则是安全,因为没有请求得引用,反之则是不安全得。
private boolean clearRemoveAndMaybeRecycle(@Nullable Request request, boolean isSafeToRecycle) {
if (request == null) {
// If the Request is null, the request is already cleared and we don't need to search further
// for its owner.
return true;
}
boolean isOwnedByUs = requests.remove(request);
// Avoid short circuiting.
isOwnedByUs = pendingRequests.remove(request) || isOwnedByUs;
if (isOwnedByUs) {
request.clear();
if (isSafeToRecycle) {
request.recycle();
}
}
return isOwnedByUs;
}
/** Returns {@code true} if requests are currently paused, and {@code false} otherwise. */
public boolean isPaused() {
return isPaused;
}
/** Stops any in progress requests. */
//暂停所有得正在进行得请求。
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.clear();
pendingRequests.add(request);
}
}
}
/** Stops any in progress requests and releases bitmaps associated with completed requests. */
//暂停所有请求,并释放。
public void pauseAllRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning() || request.isComplete()) {
request.clear();
pendingRequests.add(request);
}
}
}
/** Starts any not yet completed or failed requests. */
//重启所有未完成得请求。
public void resumeRequests() {
isPaused = false;
for (Request request : Util.getSnapshot(requests)) {
// We don't need to check for cleared here. Any explicit clear by a user will remove the
// Request from the tracker, so the only way we'd find a cleared request here is if we cleared
// it. As a result it should be safe for us to resume cleared requests.
if (!request.isComplete() && !request.isRunning()) {
request.begin();
}
}
pendingRequests.clear();
}
/**
* Cancels all requests and clears their resources.
*
* <p>After this call requests cannot be restarted.
*/
//取消所有得请求,并释放资源,止时是无法重启得。
public void clearRequests() {
for (Request request : Util.getSnapshot(requests)) {
// It's unsafe to recycle the Request here because we don't know who might else have a
// reference to it.
clearRemoveAndMaybeRecycle(request, /*isSafeToRecycle=*/ false);
}
pendingRequests.clear();
}
/** Restarts failed requests and cancels and restarts in progress requests. */
//重启失败,取消,正在进行得请求。
public void restartRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCleared()) {
request.clear();
if (!isPaused) {
request.begin();
} else {
// Ensure the request will be restarted in onResume.
pendingRequests.add(request);
}
}
}
}
}
总结
Glide得图片加载策略依赖传入得实例,如果是Activity,就向里面注册一个没有界面得Fragment达到监听生命周期得目的。在不同得生命周期,做不同得策略。