本文首發於 vivo互聯網技術 微信公衆號
連接:https://mp.weixin.qq.com/s/uTv44vJFFJI_l6b5YKSXYQ
做者:連凌能java
Android App中圖片的展現是很基本也很重要的一個功能,在Android平臺上有不少的圖片加載解決方案,可是官方承認的是Glide。Android App的頁面是有生命週期的,Glide比較好的一個功能就是具備生命週期管理功能,可以根據頁面和APP的生命週期來管理圖片的加載和中止,也開放接口供用戶在內存緊張時手動進行內存管理。本文重點是生命週期源碼的分析,不會從簡單的使用着手。android
這是Glide源碼分析的第二篇文章,第一篇是《Glide緩存流程》,從資源的獲取流程對源碼進行分析。本篇會聚焦於生命週期模塊的原理。開始以前先思考下面這幾個問題:緩存
Glide怎麼實現頁面生命週期?微信
Glide爲何對Fragment作緩存?網絡
Glide如何監聽網絡變化?app
先來看with函數的執行, 會構造glide單例,而 ide
RequestManagerRetriever在initializeGlide中會進行構造。函數
// Glide.java public static RequestManager with(@NonNull Activity activity) { return getRetriever(activity).get(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(); } @NonNull public static Glide get(@NonNull Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { checkAndInitializeGlide(context); } } } return glide; } private static void checkAndInitializeGlide(@NonNull Context context) { // In the thread running initGlide(), one or more classes may call Glide.get(context). // Without this check, those calls could trigger infinite recursion. if (isInitializing) { throw new IllegalStateException("You cannot call Glide.get() in registerComponents()," + " use the provided Glide instance instead"); } isInitializing = true; initializeGlide(context); isInitializing = false; }
構造完成RequestManagerRetriever經過get返回一個 RequestManager, 若是不在主線程,默認會傳入 getApplicationContext,也就是不進行生命週期管理:oop
在getRequestManagerFragment中先查看當前Activity中有沒有FRAGMENT_TAG這個標籤對應的Fragment,若是有就直接返回源碼分析
若是沒有,會判斷pendingRequestManagerFragments中有沒有,若是有就返回
// RequestManagerRetriever.java @NonNull public RequestManager get(@NonNull Activity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet( activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } } private RequestManager fragmentGet(@NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { RequestManagerFragment current = getRequestManagerFragment(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; } private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { current = pendingRequestManagerFragments.get(fm); if (current == null) { current = new RequestManagerFragment(); current.setParentFragmentHint(parentHint); if (isParentVisible) { current.getGlideLifecycle().onStart(); } pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; } public boolean handleMessage(Message message) { ... switch (message.what) { case ID_REMOVE_FRAGMENT_MANAGER: android.app.FragmentManager fm = (android.app.FragmentManager) message.obj; key = fm; removed = pendingRequestManagerFragments.remove(fm); break; ... } ... }
這裏面須要注意一個問題,就是若是with()函數中傳進來的不是Activity,而是Fragment,那麼也會去建立一個沒有界面的RequestManagerFragment,而它的父Fragment就是傳進來的Fragment。
上面爲何須要pendingRequestManagerFragments先進行緩存呢?這個放到下面第二個問題中說明。先接着往下看生命週期的傳遞。
RequestManagerFragment是一個很重要的類,Glide就是經過它做爲生命週期的分發入口,RequestManagerFragment的默認構造函數會實例化一個ActivityFragmentLifecycle,在每一個生命週期onStart/onStop/onDestroy中會調用ActivityFragmentLifecycle:
// RequestManagerFragment.java public class RequestManagerFragment extends Fragment { private static final String TAG = "RMFragment"; private final ActivityFragmentLifecycle lifecycle; @Nullable private RequestManager requestManager; public RequestManagerFragment() { this(new ActivityFragmentLifecycle()); } RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) { this.lifecycle = lifecycle; } @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(); } ... }
RequestManagerFragment裏面有一個實例RequestManager,在前面的fragmentGet,RequestManagerFragment拿到之後會嘗試獲取它的RequestManager,第一次獲取確定是沒有,就會從新構造一個, 經過RequestManagerRetriever構造時傳入的RequestManagerFactory工廠類實例化一個RequestManager, 把RequestManagerFragment中的ActivityFragmentLifecycle傳進去:
// RequestManagerRetriever.java public interface RequestManagerFactory { @NonNull RequestManager build( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context); } private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() { @NonNull @Override public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) { return new RequestManager(glide, lifecycle, requestManagerTreeNode, context); } };
很明顯生命週期的關鍵就在ActivityFragmentLifecycle, 在RequestManagerFragment中相應生命週期中會回調它,那麼猜想它確定是在裏面維護了一個觀察者列表,相應事件發生的時候進行通知, 看下它的源碼:
// ActivityFragmentLifecycle.java class ActivityFragmentLifecycle implements Lifecycle { private final Set<LifecycleListener> lifecycleListeners = Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>()); private boolean isStarted; private boolean isDestroyed; @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(); } } }
因此RequestManagerFragment把這個傳給RequestManager後,確定會註冊觀察者,看一下RequestManager的相關代碼,在構造函數裏面lifecycle.addListener(this);,把本身註冊爲觀察者:
// RequestManager.java public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder<Drawable>> { ... protected final Glide glide; protected final Context context; @Synthetic final Lifecycle lifecycle; private final RequestTracker requestTracker; private final RequestManagerTreeNode treeNode; private final TargetTracker targetTracker = new TargetTracker(); private final Runnable addSelfToLifecycle = new Runnable() { @Override public void run() { lifecycle.addListener(RequestManager.this); } }; private final Handler mainHandler = new Handler(Looper.getMainLooper()); private final ConnectivityMonitor connectivityMonitor; private RequestOptions requestOptions; public RequestManager( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode treeNode, @NonNull Context context) { this( glide, lifecycle, treeNode, new RequestTracker(), glide.getConnectivityMonitorFactory(), context); } // Our usage is safe here. @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") RequestManager( Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory, Context context) { this.glide = glide; this.lifecycle = lifecycle; this.treeNode = treeNode; this.requestTracker = requestTracker; this.context = context; connectivityMonitor = factory.build( context.getApplicationContext(), new RequestManagerConnectivityListener(requestTracker)); if (Util.isOnBackgroundThread()) { mainHandler.post(addSelfToLifecycle); } else { lifecycle.addListener(this); } lifecycle.addListener(connectivityMonitor); setRequestOptions(glide.getGlideContext().getDefaultRequestOptions()); glide.registerRequestManager(this); }
在看下RequestManager對應的生命週期裏面, 在這裏面分別啓動,中止和銷燬請求:
// RequestManager @Override public void onStart() { resumeRequests(); targetTracker.onStart(); } @Override public void onStop() { pauseRequests(); targetTracker.onStop(); } @Override public void onDestroy() { targetTracker.onDestroy(); for (Target<?> target : targetTracker.getAll()) { clear(target); } targetTracker.clear(); requestTracker.clearRequests(); lifecycle.removeListener(this); lifecycle.removeListener(connectivityMonitor); mainHandler.removeCallbacks(addSelfToLifecycle); glide.unregisterRequestManager(this); }
再貼一次RequestManagerRetriever中獲取Fragment的代碼,前面留了一個疑問,爲何這裏會須要一個pendingRequestManagerFragments對Fragment進行緩存。
// RequestManagerRetriever.java /** * Pending adds for RequestManagerFragments. */ @SuppressWarnings("deprecation") @VisibleForTesting final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments = new HashMap<>(); private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { current = pendingRequestManagerFragments.get(fm); if (current == null) { current = new RequestManagerFragment(); current.setParentFragmentHint(parentHint); if (isParentVisible) { current.getGlideLifecycle().onStart(); } pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; }
咱們看一個狀況:
Glide.with(Context).load(ImageUrl1).into(imageview1); // task1 Glide.with(Context).load(ImageUrl2).into(imageview2); // task2
Android開發應該都知道主線程有一個Handler機制,會往消息隊列中放消息,經過Looper按順序取出來執行。那麼主線程中的執行順序和消息隊列中的執行順序關係是什麼?看個栗子:
private void start() { mHandler = new Handler(getMainLooper()); VLog.i("HandlerRunT", "=========Begin!============"); mHandler.post(new Runnable() { @Override public void run() { VLog.i("HandlerRunT", "=========First!============"); } }); VLog.i("HandlerRunT", "=========Middle!============"); mHandler.sendMessage(Message.obtain(mHandler, new Runnable() { @Override public void run() { VLog.i("HandlerRunT", "=========Second!============"); } })); VLog.i("HandlerRunT", "=========End!============"); Next(); } private void Next() { VLog.i("HandlerRunT", "=========Next Begin!============"); mHandler.post(new Runnable() { @Override public void run() { VLog.i("HandlerRunT", "=========Next First!============"); } }); VLog.i("HandlerRunT", "=========Next Middle!============"); mHandler.sendMessage(Message.obtain(mHandler, new Runnable() { @Override public void run() { VLog.i("HandlerRunT", "=========Next Second!============"); } })); VLog.i("HandlerRunT", "=========Next End!============"); }
在start中打印的順序和它裏面的Handler中的信息哪一個先打印?start中handler的信息和Next函數中的信息打印順序是怎樣的?看下打印結果:
HandlerRunT: =========Begin!============ HandlerRunT: =========Middle!============ HandlerRunT: =========End!============ HandlerRunT: =========Next Begin!============ HandlerRunT: =========Next Middle!============ HandlerRunT: =========Next End!============ HandlerRunT: =========First!============ HandlerRunT: =========Second!============ HandlerRunT: =========Next First!============ HandlerRunT: =========Next Second!============
Handler中的順序會在主線程以後,Handler中的消息執行順序就是隊列先進先出。
上面執行到task1的時候,在下面這兩行代碼,add操做會往消息隊列放一個消息,這裏標記爲msg1:
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
// FragmentManager.java public void enqueueAction(OpGenerator action, boolean allowStateLoss) { if (!allowStateLoss) { checkStateLoss(); } synchronized (this) { if (mDestroyed || mHost == null) { if (allowStateLoss) { // This FragmentManager isn't attached, so drop the entire transaction. return; } throw new IllegalStateException("Activity has been destroyed"); } if (mPendingActions == null) { mPendingActions = new ArrayList<>(); } mPendingActions.add(action); scheduleCommit(); } } private void scheduleCommit() { synchronized (this) { boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty(); boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1; if (postponeReady || pendingReady) { mHost.getHandler().removeCallbacks(mExecCommit); mHost.getHandler().post(mExecCommit); } } }
那麼若是不把task1中構造的RequestManagerFragment放到pendingRequestManagerFragments中,那麼在執行task2的時候也會再從新構造一個RequestManagerFragment,而且往主線程中放一個消息msg2,這個時候就會出現重複add的狀況。
因此在前面new 出來一個RequestManagerFragment,隨後就把它放到pendingRequestManagerFragments中,那麼task2再進來的時候從緩存中能取到,就不會再從新new和add了。
那麼下一個問題來了,爲何會出現下面這行代碼,add後又須要立刻發一個消息remove掉?在前面阻止掉task2重複new和add的操做後,就把這個緩存刪掉,能夠避免內存泄漏和內存壓力:
// RequestManagerRetriever.java pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
從上面頁面生命週期的分析部分知道,對於任務的控制都是經過RequestManager,仍是到它裏面去看,實現網絡變化監聽的就是ConnectivityMonitor:
// RequestManager.java public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder<Drawable>> { ... protected final Glide glide; protected final Context context; @Synthetic final Lifecycle lifecycle; private final RequestTracker requestTracker; private final RequestManagerTreeNode treeNode; private final TargetTracker targetTracker = new TargetTracker(); private final Handler mainHandler = new Handler(Looper.getMainLooper()); private final ConnectivityMonitor connectivityMonitor; ... RequestManager( Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory, Context context) { this.glide = glide; this.lifecycle = lifecycle; this.treeNode = treeNode; this.requestTracker = requestTracker; this.context = context; connectivityMonitor = factory.build( context.getApplicationContext(), new RequestManagerConnectivityListener(requestTracker)); if (Util.isOnBackgroundThread()) { mainHandler.post(addSelfToLifecycle); } else { lifecycle.addListener(this); } lifecycle.addListener(connectivityMonitor); ... }
因此也是把它註冊爲ActivityFragmentLifecycle的觀察者,ConnectivityMonitor經過ConnectivityMonitorFactory進行構造,提供了默認實現類DefaultConnectivityMonitorFactory:
// DefaultConnectivityMonitorFactory.java public class DefaultConnectivityMonitorFactory implements ConnectivityMonitorFactory { private static final String TAG = "ConnectivityMonitor"; private static final String NETWORK_PERMISSION = "android.permission.ACCESS_NETWORK_STATE"; @NonNull @Override public ConnectivityMonitor build( @NonNull Context context, @NonNull ConnectivityMonitor.ConnectivityListener listener) { int permissionResult = ContextCompat.checkSelfPermission(context, NETWORK_PERMISSION); boolean hasPermission = permissionResult == PackageManager.PERMISSION_GRANTED; return hasPermission ? new DefaultConnectivityMonitor(context, listener) : new NullConnectivityMonitor(); } }
接着就往下看DefaultConnectivityMonitor, 在onStart中registerReceiver監聽手機網絡狀態變化的廣播,而後在connectivityReceiver中調用isConnect進行網絡狀態確認,根據網絡狀態是否變化,若是有變化就回調監聽ConnectivityMonitor.ConnectivityListener:
final class DefaultConnectivityMonitor implements ConnectivityMonitor { private static final String TAG = "ConnectivityMonitor"; private final Context context; @SuppressWarnings("WeakerAccess") @Synthetic final ConnectivityListener listener; @SuppressWarnings("WeakerAccess") @Synthetic boolean isConnected; private boolean isRegistered; private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() { @Override public void onReceive(@NonNull Context context, Intent intent) { boolean wasConnected = isConnected; isConnected = isConnected(context); if (wasConnected != isConnected) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "connectivity changed, isConnected: " + isConnected); } listener.onConnectivityChanged(isConnected); } } }; DefaultConnectivityMonitor(@NonNull Context context, @NonNull ConnectivityListener listener) { this.context = context.getApplicationContext(); this.listener = listener; } private void register() { if (isRegistered) { return; } // Initialize isConnected. isConnected = isConnected(context); try { // See #1405 context.registerReceiver(connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); isRegistered = true; } catch (SecurityException e) { // See #1417, registering the receiver can throw SecurityException. if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Failed to register", e); } } } private void unregister() { if (!isRegistered) { return; } context.unregisterReceiver(connectivityReceiver); isRegistered = false; } @SuppressWarnings("WeakerAccess") @Synthetic // Permissions are checked in the factory instead. @SuppressLint("MissingPermission") boolean isConnected(@NonNull Context context) { ConnectivityManager connectivityManager = Preconditions.checkNotNull( (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)); NetworkInfo networkInfo; try { networkInfo = connectivityManager.getActiveNetworkInfo(); } catch (RuntimeException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Failed to determine connectivity status when connectivity changed", e); } // Default to true; return true; } return networkInfo != null && networkInfo.isConnected(); } @Override public void onStart() { register(); } @Override public void onStop() { unregister(); } @Override public void onDestroy() { // Do nothing. } }
ConnectivityMonitor.ConnectivityListener是在RequestManager中傳入,有網絡從新鏈接後重啓請求:
// RequestManager.java private static class RequestManagerConnectivityListener implements ConnectivityMonitor .ConnectivityListener { private final RequestTracker requestTracker; RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) { this.requestTracker = requestTracker; } @Override public void onConnectivityChanged(boolean isConnected) { if (isConnected) { requestTracker.restartRequests(); } } }
在Glide構造的時候會調用registerComponentCallbacks進行全局註冊, 系統在內存緊張的時候回調onTrimMemory,而後根據系統內存緊張級別進行memoryCache/bitmapPool/arrayPool的回收:
// Glide.java public static Glide get(@NonNull Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { checkAndInitializeGlide(context); } } } return glide; } private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) { Context applicationContext = context.getApplicationContext(); ... applicationContext.registerComponentCallbacks(glide); Glide.glide = glide; } @Override public void onTrimMemory(int level) { trimMemory(level); } public void trimMemory(int level) { Util.assertMainThread(); memoryCache.trimMemory(level); bitmapPool.trimMemory(level); arrayPool.trimMemory(level); }
再回顧前面的四個問題,我相信聰明的你已經有了答案,文章的各小節標題就是根據問題來進行分析的,這麼就再也不贅述了,要不有湊字數的嫌疑。Glide的源碼是比較龐大並且高質量的,因此一兩篇文章是說不清楚的,後面對於Glide的源碼分析還會有後續的文章,歡迎關注。