深入解析Glide生命周期管理

  1. 云栖社区>
  2. 博客>
  3. 正文

深入解析Glide生命周期管理

Android进阶开发 2020-04-03 15:54:08 浏览477
展开阅读全文

作者:他的大姨父
链接:https://www.jianshu.com/p/317b2d6bde1b

本文是Glide源码解析系列的第一篇,通过这篇文档,将可以了解到:

  • 1.Glide如何绑定Activity、Fragment生命周期。
  • 2.Glide如何监听内存变化、网络变化。
  • 3.Glide如何处理请求的生命周期。

1.0 生命周期相关UML类图

2.0 生命周期绑定

Glide生命周期绑定是从入口单例类Glide开始的,通过with()多个重载方法来实现对生命周期的绑定工作。

public static RequestManager with(Fragment fragment)  
public static RequestManager with(FragmentActivity activity)  
public static RequestManager with(Activity activity)  
public static RequestManager with(Context context)

以Activity的参数为例:

public static RequestManager with(Activity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}

RequestManagerRetriever是一个单例类,可以理解为一个工厂类,通过get方法接收不同的参数,来创建RequestManager。

public RequestManager get(Activity activity) {
    if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        return get(activity.getApplicationContext());
    } else {
        assertNotDestroyed(activity);
        android.app.FragmentManager fm = activity.getFragmentManager();
        return fragmentGet(activity, fm);
    }
}
public RequestManager get(android.app.Fragment fragment) {
    if (fragment.getActivity() == null) {
        throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
    }
    if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        return get(fragment.getActivity().getApplicationContext());
    } else {
        android.app.FragmentManager fm = fragment.getChildFragmentManager();
        return fragmentGet(fragment.getActivity(), fm);
    }
}

如果是在子线程进行的with操作,那么Glide将默认使用ApplicationContext,可以理解为不对请求的生命周期进行管理,通过Activity拿到FragmentManager,并将创建RequestManager的任务传递下去。最终都走到了fragmentGet方法,注意细微区别是Activity传的参数的是Activity的FragmentManager,Fragment传的参数的是ChildFragmentManager,这两者不是一个东西。

RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
    //获取RequestManagerFragment,并获取绑定到这个fragment的RequestManager
    RequestManagerFragment current = getRequestManagerFragment(fm);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
    //如果获取RequestManagerFragment还没有绑定过RequestManager,那么就创建RequestManager并绑定到RequestManagerFragment
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

2.0.1 创建RequestManagerFragment

这个方法创建了一个fragment,并且创建并绑定了一个RequestManager,看看getRequestManagerFragment如何获取的RequestManagerFragment。

RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
    //尝试根据id去找到此前创建的RequestManagerFragment
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
        //如果没有找到,那么从临时存储中寻找
        current = pendingRequestManagerFragments.get(fm);
        if (current == null) {
            //如果仍然没有找到,那么新建一个RequestManagerFragment,并添加到临时存储中。
            //然后开启事务绑定fragment并使用handler发送消息来将临时存储的fragment移除。
            current = new RequestManagerFragment();
            pendingRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}

这里有个问题,为什么需要使用pendingRequestManagerFragments这样一个集合来临时存储一下fragment,然后又马上通过handler发送消息移除?这其实是跟主线程的Looper机制和Fragment的事务机制有关的(点击这里查看Fragment事务流程分析)。我们知道,android中的主线程是一个闭环,通过Handler发送消息到MessageQueue,然后通过Looper轮询获取消息并交给Handler处理(点击这里查看Activity启动流程分析)。如下面一个常见场景:

Glide.with(this).load(url_1).into(mImageView_1);
Glide.with(this).load(url_2).into(mImageView_2);

这段代码通过Glide加载了两张图片并设置到了两个ImageView上,当以上代码块执行时,其所属的代码群的Message刚刚从MessageQueue中取出正在被处理,我们假设这个Message为m1,并且这个MessageQueue中没有其他消息。此时情形是这样的:

当代码执行到getRequestManagerFragment这个方法时,会通过开启事务的方式来绑定这个fragment到activity,相关源码如下(有兴趣了解的点击这里查看Fragment事务流程分析),这个方法在FragmentManagerImpl.java中:

public void enqueueAction(Runnable action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        checkStateLoss();
    }
    synchronized (this) {
        if (mDestroyed || mHost == null) {
            throw new IllegalStateException("Activity has been destroyed");
        }
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<Runnable>();
        }
        mPendingActions.add(action);
        if (mPendingActions.size() == 1) {
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
        }
    }
}

这里的mHost其实就是activity创建的,并且持有activity以及mMainHandler的引用,根据上述代码可以知道,其实绑定fragment的操作最终是通过主线程的handler发送消息处理的,我们假设这个消息为m2。然后handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();这句代码发送的消息为m3。那么当Glide.with(this).load(url_1).into(mImageView_1);这句代码执行这里时,消息队列有了变化:

但是m2这个消息并不会马上被处理,这是因为m1还有代码还没有执行完毕,也就是说这个fragment并不会马上被绑定,此时m1继续向下执行到第二句代码Glide.with(this).load(url_2).into(mImageView_2);当这句代码走到getRequestManagerFragment时,如果在m1时,我们不将fragment临时存储在pendingRequestManagerFragments中,由于m2还没有被处理,那么

RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);

必然是找不到这个fragment的,那么就会导致重新创建一个新的重复的fragment,并开启事务绑定,这显然是不合情理的,因为Glide需要保证rootFragment的唯一性,rootFragment即fragment依附或者没有fragment依附的activity所创建的最上层RequestManagerFragment。
接着往下看RequestManagerFragment的构造方法做了什么。

public RequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
}

直接创建一个ActivityFragmentLifecycle,这个类实际是一个生命周期回调的管理类,实现了Lifecycle接口。所有的LifecycleListener会添加到一个集合中,当RequestManagerFragment生命周期方法触发时,会调用ActivityFragmentLifecycle相应生命周期方法,这个方法然后再遍历调用所有LifecycleListener的生命周期方法,以onStart生命周期方法为例,RequestManagerFragment中:

public void onStart() {
    super.onStart(); 
    lifecycle.onStart();
}

然后ActivityFragmentLifecycle中:

void onStart() {
    isStarted = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
        lifecycleListener.onStart();
    }
}

2.0.2 rootRequestManagerFragment

上面UML图上,可以知道RequestManagerFragment还有一个rootRequestManagerFragment的成员变量,Glide每创建一个RequestManagerFragment,都会尝试实例化rootRequestManagerFragment,这个fragment即顶级的Activity所创建的RequestManagerFragment,相关代码:

public void onAttach(Activity activity) {
    super.onAttach(activity);
    rootRequestManagerFragment = RequestManagerRetriever.get()
            .getRequestManagerFragment(getActivity().getFragmentManager());
    if (rootRequestManagerFragment != this) {
        rootRequestManagerFragment.addChildRequestManagerFragment(this);
    }
}

@Override
public void onDetach() {
    super.onDetach();
    if (rootRequestManagerFragment != null) {
        rootRequestManagerFragment.removeChildRequestManagerFragment(this);
        rootRequestManagerFragment = null;
    }
}

可以看到,不管当前的RequestManagerFragment是通过何种方式创建的,都会在OnAttach时,拿到当前所绑定的Activity的FragmentManager来初始化一个RequestManagerFragment,这个RequestManagerFragment有可能是自身,有可能已经被初始化过了,比如是通过with(Activity activity)的方式初始化的,那么很显然

RequestManagerRetriever.get().getRequestManagerFragment(getActivity().getFragmentManager());

这句代码拿到的会是自己本身,而如果是通过with(Fragment fragment)的形式创建的,rootRequestManagerFragment将指向当前fragment绑定到Activity所绑定的RequestManagerFragment,如果该Activity没有绑定过,那么会开启事务绑定一个RequestManagerFragment。并且如果自己不是rootRequestManagerFragment的话,那么将会把自己保存到rootRequestManagerFragment中的一个集合:

private void addChildRequestManagerFragment(RequestManagerFragment child) {
    childRequestManagerFragments.add(child);
}

简而言之,Glide会为Activity创建一个RequestManagerFragment做为rootFragment,并保存该Activity底下所有Fragment(如果有的话)所创建的RequestManagerFragment。

2.0.3 RequestManagerTreeNode

RequestManagerFragment初始化时,还会初始化RequestManagerTreeNode,顾名思义,这个类是用来保存请求树节点的,比如一个Activity采用Viewpager + Fragment的形式,而里面的Fragment又是一个ViewPager + Fragment的形式,这个时候,假设其中一个RequestManagerFragment生命周期方法走了,怎么知道哪些RequestManagerFragment绑定的LifeCycle应该得到调用呢?理想的情况是,应该让绑定该RequestManagerFragment的Fragment所有的子Fragment的RequestManagerFragment的生命周期得到调用,比如如下场景中,Activity中各有两个Fragment,两个Fragment又各有两个子Fragment,在所有Fragment中,均通过with(this)的方式来加载图片,经过之前的分析我们可以知道的是,ROOT RMF 中会保存有6个RMF(RMF即RequestManagerFragment):

当如果F1 RMF生命周期做出反应时,因为RequestManagerFragment是无界面的,所以可以理解为F1的生命周期做出反应。我们希望F11和F12所绑定的RequestManagerFragment也要立即做出反应。但是F2以及其底下的RequestManagerFragment则不应响应对应生命周期事件,我们知道任何一个RequestManagerFragment可以通过rootRequestManagerFragment拿到这6个RMF,继而拿到其所对应的RequestManager,那么怎么去确定F11 RMF 和 F12 RMF呢?这就是RequestManagerTreeNode干的事情了,RequestManagerFragment中的非静态内部类FragmentRequestManagerTreeNode实现了RequestManagerTreeNode:

private class FragmentRequestManagerTreeNode implements RequestManagerTreeNode {
    @Override
    public Set<RequestManager> getDescendants() {
        Set<RequestManagerFragment> descendantFragments = getDescendantRequestManagerFragments();
        HashSet<RequestManager> descendants =
            new HashSet<RequestManager>(descendantFragments.size());
        for (RequestManagerFragment fragment : descendantFragments) {
            if (fragment.getRequestManager() != null) {
                descendants.add(fragment.getRequestManager());
            }
        }
        return descendants;
    }
}

这个类做的事情比较简单,调用外部类RequestManagerFragment的方法getDescendantRequestManagerFragments拿到所有的“后裔”Fragment,然后再取出它的RequestManager,然后集合装起来返回,这里的后裔在前面的例子中,指的就是F11 RMF 和 F12 RMF,看看getDescendantRequestManagerFragments是怎么拿到的F11和F12:

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public Set<RequestManagerFragment> getDescendantRequestManagerFragments() {
    //如果自己是rootFragment,那么直接返回childRequestManagerFragments
    if (rootRequestManagerFragment == this) {
        return Collections.unmodifiableSet(childRequestManagerFragments);
    } else if (rootRequestManagerFragment == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        // Pre JB MR1 doesn't allow us to get the parent fragment so we can't introspect hierarchy, so just
        // return an empty set.
        return Collections.emptySet();
    } else {
        HashSet<RequestManagerFragment> descendants = new HashSet<RequestManagerFragment>();
        for (RequestManagerFragment fragment
                //遍历取出rootFragment中的RMF,并获取到其parentFragment,找出后裔。
                : rootRequestManagerFragment.getDescendantRequestManagerFragments()) {
            if (isDescendant(fragment.getParentFragment())) {
                descendants.add(fragment);
            }
        }
        return Collections.unmodifiableSet(descendants);
    }
}

看看isDescendant方法是如何判断的:

private boolean isDescendant(Fragment fragment) {
    Fragment root = this.getParentFragment();
    while (fragment.getParentFragment() != null) {
        if (fragment.getParentFragment() == root) {
            return true;
        }
        fragment = fragment.getParentFragment();
    }
    return false;
}

依上面的例子,当遍历到F11 RMF时,参数传递过来的是F11,root 则为F1,F11再拿到parent,也是F1,返回true,F12 RMF类似也返回true;
当遍历到F21 RMF时,参数传入F21,root仍是F1,此时F21再怎么拿Parent也不可能是root,返回false。
简而言之,RequestManagerTreeNode用来获取绑定该RequestManagerFragment的Fragment的所有子Fragment所绑定的RequestManagerFragment所绑定的RequestManager

2.0.4 RequestManager

上面一直在说RequestManagerFragment,下面回到FragmentGet方法中,再贴一次,免得上翻麻烦:

RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
    //获取RequestManagerFragment,并获取绑定到这个fragment的RequestManager
    RequestManagerFragment current = getRequestManagerFragment(fm);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
    //如果获取RequestManagerFragment还没有绑定过RequestManager,那么就创建RequestManager并绑定到RequestManagerFragment
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

根据上面的UML图,可以知道RequestManager是一个非常核心的类,并且还实现了LifecycleListener来处理请求的生命周期。上述代码在创建RequestManager时,传递了3个参数,分别是context,前面分析过的初始化RequestManagerFragment所创建的LifeCycle和RequestManagerTreeNode。直接看RequestManager的构造函数:

public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
    this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
}

调用的另一个构造方法,并增加了两个新的参数RequestTracker和ConnectivityMonitorFactory。

RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
        RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
    this.context = context.getApplicationContext();
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.glide = Glide.get(context);
    this.optionsApplier = new OptionsApplier();

    ConnectivityMonitor connectivityMonitor = factory.build(context,
            new RequestManagerConnectivityListener(requestTracker));

    // If we're the application level request manager, we may be created on a background thread. In that case we
    // cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
    // ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
    if (Util.isOnBackgroundThread()) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                lifecycle.addListener(RequestManager.this);
            }
        });
    } else {
        lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);
}

RequestTracker即所有请求操作的真正处理者,所有Request的暂停取消执行操作都由RequestTracker来完成,如RequestManager暂停请求的实现:

public void pauseRequests() {
    Util.assertMainThread();
    requestTracker.pauseRequests();
}

2.0.5 网络状态监测

请求生命周期的实现细节后面再说,暂时埋坑,先来看看ConnectivityMonitorFactory这个工厂生产了什么。

public class ConnectivityMonitorFactory {
    public ConnectivityMonitor build(Context context,     ConnectivityMonitor.ConnectivityListener listener) {
        final int res = context.checkCallingOrSelfPermission("android.permission.ACCESS_NETWORK_STATE");
        final boolean hasPermission = res == PackageManager.PERMISSION_GRANTED;
        if (hasPermission) {
            return new DefaultConnectivityMonitor(context, listener);
        } else {
            return new NullConnectivityMonitor();
            }
    }
}

很简单,接收一个ConnectivityListener根据是否有监控网络状态的权限来创建相应的网络监控器。
DefaultConnectivityMonitor也比较简单,就是内部定义了一个广播接收者,并且也实现了lifeCycleListener。在上面RequestManager的构造方法中,创建了一个RequestManagerConnectivityListener:

private static class RequestManagerConnectivityListener implements ConnectivityMonitor.ConnectivityListener {
    private final RequestTracker requestTracker;

    public RequestManagerConnectivityListener(RequestTracker requestTracker) {
        this.requestTracker = requestTracker;
    }

    @Override
    public void onConnectivityChanged(boolean isConnected) {
        if (isConnected) {
            requestTracker.restartRequests();
        }
    }
}

这个listener很简单,收到网络状态连接就重启请求。然后通过工厂创建出了DefaultConnectivityMonitor,并把它添加到了lifecycle中。到这里,Glide监测网络状态来重启请求的实现方式就呼之欲出了,大体步骤如下:
在相应的生命周期方法中,会调用lifecycle的生命周期方法,lifecycle会调用DefaultConnectivityMonitor所实现的相应生命周期方法来注册及解除注册网络状态的广播接收者,收到广播后,会回调之前传递的参数ConnectivityListener的onConnectivityChanged方法来处理Request。

2.0.6 内存状态监测

RequestManager中还存有Glide这个入口类的实例,构造方法中直接获取到的,用来对内存状态的变更作出处理,比较简单,看看流程便可以了,以onTrimMemory为例,
当RequestManagerFragment的onTrimMemory被调用时,会调用其绑定的RequetManager的相应方法来处理:

@Override
public void onTrimMemory(int level) {
    // If an activity is re-created, onTrimMemory may be called before a manager is ever set.
    // See #329.
    if (requestManager != null) {
        requestManager.onTrimMemory(level);
    }
}

然后RequestManager再调用Glide入口类的trimMemory来释放更多内存:

public void onTrimMemory(int level) {
    glide.trimMemory(level);
}

2.0.7 生命周期回调流程总结

在RequestManager构造方法中,还会将自身添加到LifeCycle中,这样,整个流程就畅通了:

细心的可以发现,虽然在构造RequestManager时传递了参数RequestManagerTreeNode,但是在这个回调流程中,并没有对所有后裔RMF的RequestManager进行调用,Glide默认确实是不会去调用,但这里并不意味着这些RequestManager不会被调用到,事实上,当前RMF生命周期被调用时,就意味后裔Fragment生命周期也会被调用,那么后裔Fragment这个流程仍然会走一遍,那么RequestManagerTreeNode到底有什么用呢?答案是没用,完全没用,如果只是简单使用Glide的话。当然,RequestManager暴露了相关接口给开发者使用:

public void resumeRequestsRecursive() {
    Util.assertMainThread();
    resumeRequests();
    for (RequestManager requestManager : treeNode.getDescendants()) {
        requestManager.resumeRequests();
    }
}

调用这个方法将会把所有后裔的请求同时一起处理。

**推荐阅读:[2017-2020历年字节跳动Android面试真题解析(累计下载1082万次,持续更新中)
](https://www.jianshu.com/p/7f9ade51232e)**
2020最新Android大厂高频面试题解析大全(BAT TMD JD 小米)

网友评论

登录后评论
0/500
评论