zoukankan      html  css  js  c++  java
  • AsyncTaskLoader设计原理大揭秘

    简介

    Android异步处理之AsyncTaskLoader简单使用中我简单的介绍了一下AsyncTaskLoader的基本用法和使用场景,对AsyncTaskLoader还不是很熟悉的小伙伴可以先简单学习一下。

    相信读过Android异步处理之AsyncTaskLoader简单使用后,大家对烤面包机,面包师,面包房的例子还是有点印象的,那么接下来趁热打铁,继续沿用这个买面包的例子讲述一下AsyncTaskLoader的设计原理。

    设计原理

    在讲设计原理之前,先简单了解一下AsyncTaskLoader的父类Loader

        A class that performs asynchronous loading of data. While Loaders are active they should monitor the source of their data and deliver new results when the contents change. See LoaderManager for more detail. 
    

    简单理解一下Loader就是用来异步加载数据的,当Loader处于活动状态的时候需要监视数据并且在数据发生改变时加载和分发新的数据。在上述描述中我们还发现了LoaderManager这个对象,正是因为有了它,Loader才具有生命力。

    下面看一下LoaderManager的简单介绍:

       Interface associated with an Activity or Fragment for managing one or more Loader instances associated with it. This helps an application manage longer-running operations in conjunction with the Activity or Fragment lifecycle; the most common use of this is with a CursorLoader, however applications are free to write their own loaders for loading other types of data. While the LoaderManager API was introduced in HONEYCOMB, a version of the API at is also available for use on older platforms through FragmentActivity. See the blog post Fragments For All for more details. 
    

    简单理解一下就是说LoaderManager是配合着Activity,Fragment 的生命周期来管理Loader

    接下来用一张类图来简单展示一下Loader,AsyncTaskLoader,AsyncTask,LoaderManager,Activity之间的关系

    图-1 相关类之间的关系
    类关系图

    接口

    1.OnLoadCompleteListener

    被声明在Loader中,用于Loader加载完数据后回调,从上图可以看出LoaderInfo实现了这个接口,说明当Loader完成数据加载后会回调LoaderInfoonLoadComplete()方法。

    2.LoaderCallbacks

    被声明在LoaderManager中,从上图的LoaderInfo中可以看到 mCallbacks这个变量,它便是LoaderCallbacks的引用,用于当Loader加载完数据后回调上面提及的onLoadComplete(),最终回调onLoadFinished()方法将最新加载的数据传递给客户端。

    1.Loader

    抽象类负责定义相关接口和约束。其变量mListener就是加载完数据的回调。那具体是如何回调的呢?答案就在deliverResult()方法中

    Loader.java
    --------------------------
        public void deliverResult(D data) {
            if (mListener != null) {
                mListener.onLoadComplete(this, data);
            }
        }
    

    再看registerListener()方法:

    Loader.java
    --------------------------
        public void registerListener(int id, OnLoadCompleteListener<D> listener) {
            if (mListener != null) {
                throw new IllegalStateException("There is already a listener registered");
            }
            mListener = listener;
            mId = id;
        }
    

    外部就是通过调用LoaderregisterListener()方法将OnLoadCompleteListener接口注册进来的。

    2.AsyncTaskLoader

    继承自Loader,其中变量mTask正是AsyncTask类型,这里也论证了Android异步处理之AsyncTaskLoader简单使用中的说法,将AsyncTaskLoader比作面包师的话AsyncTask就是烤面包机的说法。AsyncTaskLoader中就是通过AsyncTask来完成异步加载数据这个操作的。

    3.LoaderInfo

    LoaderInfo其实是对Loader的一个封装,它掌握了Loader一系列的工作状态如:

    LoaderInfo.java
    -----------------------------
     boolean mHaveData;
     boolean mDeliveredData;
     Object mData;
     boolean mStarted;
     boolean mRetaining;
     boolean mRetainingStarted;
     boolean mReportNextStart;
     boolean mDestroyed;
     boolean mListenerRegistered;
    

    还有一系列的动作指令:

    LoaderInfo.java
    -----------------------------
    void start() {...}
    void retain() {...}
    void reportStart() {...}
    void stop() {...}
    void cancel() {...}
    void destroy() {...}
    

    4.LoaderManager和LoaderManagerImpl

    LoaderManager定义了作为Loader的管理者应该有哪些操作,而LoaderManagerImpl则具体实现这些操作。如果说把Loader比作面包师的话,那LoaderManager就算是面包店的老板吧,厨师什么时候该上班,什么时候该下班都由他管。
    其中mLoaders变量为一个数组,用于保存 多个Loader这也说明了一个面包店可以有多个面包师负责制作不同类型的面包如:
    不同的面包种类
    这么多种类的面包如果让一个面包师来做我看他也会累的够呛。

    运行流程梳理

    在接下来的几步中有任何的疑惑都可以回过头看看【图1】。

    1

    那么了解上述这些类是干嘛的以后我们就来看看当这些个类运行起来是一个怎样的流程吧。
    我们还是接着Android异步处理之AsyncTaskLoader简单使用中的例子来讲。一切起源起于onCreate()(至少对于APP开发来说是这样),那就从MainActivityonCreate()来看起吧。

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //这里假设面包房刚开门的时候已经有9个人在排队了。
            mNeededBreads = 9;
            mBaker = new Baker(this, mBreadCallback);
            mBakery = new Bakery(mBaker);
            //1.实现`LoaderCallbacks`接口。
            mCallbacks = new LoaderCallbacks<List<Bread>>() {
                @Override
                public Loader<List<Bread>> onCreateLoader(int id, Bundle args) {
                    if (mBaker == null) {
                        mBaker = new Baker(MainActivity.this, mBreadCallback);
                    }
                    return mBaker;
                }
    
                @Override
                public void onLoadFinished(Loader<List<Bread>> loader, List<Bread> data) {
                    mNeededBreads = 0 ;
                    Log.d("scott", "sell " + data.size() + " breads") ;
                }
    
                @Override
                public void onLoaderReset(Loader<List<Bread>> loader) {
    
                }
            };
            //2.在`LoaderManager`中注册这个接口。
            getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
            //3.模拟源源不断的顾客
            mockCustomer();
        }
    

    这一步主要做了三件事情:
    1.实现LoaderCallbacks接口。
    2.在LoaderManager中注册这个接口。
    3.模拟源源不断的顾客
    那么这里的mCallbacks充当了什么角色呢?其实它应该相当于一个面包师Loader和面包房店长LoaderManager的中间桥梁。当店长需要面包师的时候就会调用onCreateLoader()来获得一个面包师。同样当面包师完成面包的烤制工作后就会调用onLoadFinished()来告诉店长面包做好了。但实际情况应该不会如此,面包做好了服务员应该会直接将面包传递给顾客。

    2

    接下来我们看一下restartLoader()这个方法:

    LoaderManager.java
    --------------------------------------------------------------
        public <D> Loader<D> restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
            LoaderInfo info = mLoaders.get(id);
            //...省略部分代码
            info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
            return (Loader<D>)info.mLoader;
        }
    

    这里直接调用了createAndInstallLoader()方法来生成一个LoaderInfo对象。接着看createAndInstallLoader()方法:

    LoaderManager.java
    --------------------------------------------------------------
        private LoaderInfo createAndInstallLoader(int id, Bundle args,
                LoaderManager.LoaderCallbacks<Object> callback) {
            try {
                mCreatingLoader = true;
                //1.创建LoaderInfo对象
                LoaderInfo info = createLoader(id, args, callback);
                //2.安装LoaderInfo对象
                installLoader(info);
                return info;
            } finally {
                mCreatingLoader = false;
            }
        }
    

    3

    这里分两步来看:
    1.创建LoaderInfo对象

    LoaderInfo.java
    ------------------------------------------------------------
        private LoaderInfo createLoader(int id, Bundle args,
                LoaderManager.LoaderCallbacks<Object> callback) {
            //实例化LoaderInfo,并将id,args,callback赋值给mId,mArgs,mCallbacks
            LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
            //这里的callback就是上面onCreate中的mCallbacks
            //获得Loader实例Baker
            Loader<Object> loader = callback.onCreateLoader(id, args);
            //将Baker赋值给info中的mLoader字段
            info.mLoader = (Loader<Object>)loader;
            return info;
        }
    

    2.安装LoaderInfo对象

    LoaderInfo.java
    ------------------------------------------------------------
        void installLoader(LoaderInfo info) {
            //将info放入mLoaders数组
            mLoaders.put(info.mId, info);
            //这一步mStarted=false,不会走下面的if条件语句,那么到这里一切都结束了?
            if (mStarted) {
                // The activity will start all existing loaders in it's onStart(),
                // so only start them here if we're past that point of the activitiy's
                // life cycle
                info.start();
            }
        }
    

    4

    到这里其实我们已经不能在往下跟代码了,因为此时的mStarted=false,也就是说不会走info.start()这个方法。那么数据是在什么时候被加载的呢?冷静看上面的这段英文注释,Activity会在它的onStart()方法中启动所有已经存在的Loader,真是山穷水尽疑无路,柳暗花明又一村。我们就去onStart()中看个究竟。

    Activity.java
    ------------------------------------------------------
        protected void onStart() {
            if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
            mCalled = true;
    
            if (!mLoadersStarted) {
                mLoadersStarted = true;
                if (mLoaderManager != null) {
                    //看这里o(^▽^)o
                    mLoaderManager.doStart();
                } else if (!mCheckedForLoaderManager) {
                    mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
                }
                mCheckedForLoaderManager = true;
            }
    
            getApplication().dispatchActivityStarted(this);
        }
    

    继续LoaderManagerdoStart()方法:

    LoaderManager.java
    --------------------------------------------------------------
        void doStart() {
            if (DEBUG) Log.v(TAG, "Starting in " + this);
            if (mStarted) {
                RuntimeException e = new RuntimeException("here");
                e.fillInStackTrace();
                Log.w(TAG, "Called doStart when already started: " + this, e);
                return;
            }
            
            mStarted = true;
    
            // Call out to sub classes so they can start their loaders
            // Let the existing loaders know that we want to be notified when a load is complete
            //看,在这里LoaderInfo被启动了
            for (int i = mLoaders.size()-1; i >= 0; i--) {
                mLoaders.valueAt(i).start();
            }
        }
    

    5

    下面转移战场进入LoaderInfo看看

    
    LoaderInfo.java
    --------------------------------------------
            void start() {
            
                //...
                mStarted = true;
                if (mLoader == null && mCallbacks != null) {
                   mLoader = mCallbacks.onCreateLoader(mId, mArgs);
                }
                if (mLoader != null) {
                    //...
                    if (!mListenerRegistered) {
                        //将OnLoadCompleteListener接口注册给Loader
                        mLoader.registerListener(mId, this);
                        //将OnLoadCanceledListener接口注册给Loader
                        mLoader.registerOnLoadCanceledListener(this);
                        mListenerRegistered = true;
                    }
                    //开始加载,实质性的一步。
                    mLoader.startLoading();
                }
            }
    

    6

    进入LoaderstartLoading()方法看看:

    Loader.java
    --------------------------------------------
        public final void startLoading() {
            mStarted = true;
            mReset = false;
            mAbandoned = false;
            onStartLoading();
        }
    

    7

    接着看onStartLoading():

    Loader.java
    --------------------------------------------
         /**
         * Subclasses must implement this to take care of loading their data,
         * as per {@link #startLoading()}.  This is not called by clients directly,
         * but as a result of a call to {@link #startLoading()}.
         */
        protected void onStartLoading() {
        }
    

    注释写的很清楚,子类必须要覆盖这个方法,接着我们看看我们久违的Baker(比忘了Baker可是Loader的子类啊)吧:

    Baker.java
    --------------------------------------------
      @Override
        protected void onStartLoading() {
            //这个可以解释为强行加载,太暴力了。
            forceLoad();
        }
    

    8

    那么forceLoad()又是哪里的呢?

    Loader.java
    --------------------------------------------
        /**
         * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
         * loaded data set and load a new one.  This simply calls through to the
         * implementation's {@link #onForceLoad()}.  You generally should only call this
         * when the loader is started -- that is, {@link #isStarted()} returns true.
         *
         * <p>Must be called from the process's main thread.
         */
        public void forceLoad() {
            onForceLoad();
        }
    

    接着看onForceLoad():

    Loader.java
    --------------------------------------------
        /**
         * Subclasses must implement this to take care of requests to {@link #forceLoad()}.
         * This will always be called from the process's main thread.
         */
        protected void onForceLoad() {
        }
    

    9

    又来这套。。。服了Google的工程师了。接着在AsyncTaskLoader中找到了onForceLoad()

    AsyncTaskLoader.java
    --------------------------------------------
        @Override
        protected void onForceLoad() {
            super.onForceLoad();
            cancelLoad();
            //这里的LoadTask继承自AsyncTask
            mTask = new LoadTask();
            if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
            //执行准备就绪的mTask
            executePendingTask();
        }
    

    接着看executePendingTask():

    AsyncTaskLoader.java
    --------------------------------------------
        void executePendingTask() {
            if (mCancellingTask == null && mTask != null) {
                //...
                //...
                //到这里mTask就真正被执行了,即烤面包机考试工作了。
                mTask.executeOnExecutor(mExecutor, (Void[]) null);
            }
        }
    

    10

    接下来我们来看一下mTask对应的类LoadTask的定义吧。

     final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
            private final CountDownLatch mDone = new CountDownLatch(1);
    
            // Set to true to indicate that the task has been posted to a handler for
            // execution at a later time.  Used to throttle updates.
            boolean waiting;
    
            /* Runs on a worker thread */
            @Override
            protected D doInBackground(Void... params) {
                if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
                try {
                    
                    D data = AsyncTaskLoader.this.onLoadInBackground();
                    if (DEBUG) Log.v(TAG, this + "  <<< doInBackground");
                    return data;
                } catch (OperationCanceledException ex) {
                    //...
                    if (DEBUG) Log.v(TAG, this + "  <<< doInBackground (was canceled)", ex);
                    return null;
                }
            }
    
            /* Runs on the UI thread */
            @Override
            protected void onPostExecute(D data) {
                if (DEBUG) Log.v(TAG, this + " onPostExecute");
                try {
                    AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
                } finally {
                    mDone.countDown();
                }
            }
    
            /* Runs on the UI thread */
            @Override
            protected void onCancelled(D data) {
                //...
            }
    
            /* Runs on the UI thread, when the waiting task is posted to a handler.
             * This method is only executed when task execution was deferred (waiting was true). */
            @Override
            public void run() {
                //...
            }
    
            /* Used for testing purposes to wait for the task to complete. */
            public void waitForLoader() {
               //...
            }
        }
    

    11

    这里有两个方法需要关注:
    1.doInBackground()方法
    用过AsyncTask的应该都了解,异步操作都是放在这里执行的,我们看一下都做了什么操作?

    D data = AsyncTaskLoader.this.onLoadInBackground();
    

    接着看onLoadInBackground:

     protected D onLoadInBackground() {
            return loadInBackground();
        }
    

    这个loadInBackground()是不是有点熟悉了?没错这就是我们在Baker中重写的方法:

    Baker.java
    ------------------------------------------------------
        @Override
        public List<Bread> loadInBackground() {
            List<Bread> breads = new ArrayList<Bread>();
            int needs = mCallback.getNeededBreads();
            for (int i = 0; i < needs; i++) {
                breads.add(new Bread());
            }
            return breads;
        }
    

    OK,到这里面包已经烤完(耗时操作),接着就看这些香喷喷的面包怎么到顾客的手里的吧?

    12

    2.onPostExecute()方法

    LoadTask.java
    -------------------------------------------------
            @Override
            protected void onPostExecute(D data) {
                if (DEBUG) Log.v(TAG, this + " onPostExecute");
                try {
                    AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
                } finally {
                    mDone.countDown();
                }
            }
    

    走的是dispatchOnLoadComplete()方法:

    AsyncTaskLoader.java
    ------------------------------------------------------
           void dispatchOnLoadComplete(LoadTask task, D data) {
            if (mTask != task) {
                if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel");
                //容错处理
                dispatchOnCancelled(task, data);
            } else {
                if (isAbandoned()) {
                    // This cursor has been abandoned; just cancel the new data.
                    onCanceled(data);
                } else {
                    commitContentChanged();
                    mLastLoadCompleteTime = SystemClock.uptimeMillis();
                    mTask = null;
                    if (DEBUG) Log.v(TAG, "Delivering result");
                    //重点在这里
                    deliverResult(data);
                }
            }
        }
    

    13

    继续往下走 deliverResult(data):

    Loader.java
    ------------------------------------------------------
        public void deliverResult(D data) {
            if (mListener != null) {
                //这里的mListener就是之前在【5】中注册的OnLoadCompleteListener接口
                mListener.onLoadComplete(this, data);
            }
        }
    

    14

    那么自然又要转移到LoaderInfo中的onLoadComplete()中去了:

    LoaderInfo.java
    ------------------------------------------------------
            @Override
            public void onLoadComplete(Loader<Object> loader, Object data) {
                //...
    
                if (mLoaders.get(mId) != this) {
                    // This data is not coming from the current active loader.
                    // We don't care about it.
                    if (DEBUG) Log.v(TAG, "  Ignoring load complete -- not active");
                    return;
                }
                
                LoaderInfo pending = mPendingLoader;
                if (pending != null) {
                    // There is a new request pending and we were just
                    // waiting for the old one to complete before starting
                    // it.  So now it is time, switch over to the new loader.
                    //...
                    return;
                }
                
                // Notify of the new data so the app can switch out the old data before
                // we try to destroy it.
                if (mData != data || !mHaveData) {
                    mData = data;
                    mHaveData = true;
                    if (mStarted) {
                        //重点看这里
                        callOnLoadFinished(loader, data);
                    }
                }
    
                //if (DEBUG) Log.v(TAG, "  onLoadFinished returned: " + this);
    
                // We have now given the application the new loader with its
                // loaded data, so it should have stopped using the previous
                // loader.  If there is a previous loader on the inactive list,
                // clean it up.
                //...
            }
    

    15

    继续看callOnLoadFinished()

    LoaderInfo.java
    ------------------------------------------------------
            void callOnLoadFinished(Loader<Object> loader, Object data) {
                if (mCallbacks != null) {
                    //...
                    try {
                        if (DEBUG) Log.v(TAG, "  onLoadFinished in " + loader + ": "
                                + loader.dataToString(data));
                        //这里是重点了
                        mCallbacks.onLoadFinished(loader, data);
                    } finally {
                       //...
                    }
                    mDeliveredData = true;
                }
    

    mCallbacks又是什么呢?在第【3】步中的:

    //实例化LoaderInfo,并将id,args,callback赋值给mId,mArgs,mCallbacks
            LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
    

    而这里的callback就是我们在第【1】步中定义的mCallbacks 对象。
    饶了这么大一圈,最后还是走到了第【1】步中的:

     @Override
        public void onLoadFinished(Loader<List<Bread>> loader, List<Bread> data) {
            mNeededBreads = 0 ;
            //此时面包以成功送至顾客手中(相当于将数据更新在UI上,这里是main线程大家大可放心使用这些数据)
            Log.d("scott", "sell " + data.size() + " breads") ;
        }
    

    那么到此为止这个流程就走完了。

    总结

    1.Loader可以配合中Activity或Fragment的生命周期来加载数据。
    2.读源码的时候画类关系图很重要!读源码的时候画类关系图很重要!读源码的时候画类关系图很重要!
    3.文章写的仓促,如果有有问题的地方欢迎指出。

  • 相关阅读:
    COOKIE和SESSION有什么区别?
    JSP中三大指令
    JSP中out.print()、out.println()以及out.write()的区别
    Linux实战教学笔记06:Linux系统基础优化
    Linux实战教学笔记05:远程SSH连接服务与基本排错(新手扫盲篇)
    Linux实战教学笔记04:Linux命令基础
    Linux实战教学笔记03:操作系统发展历程及系统版本选择
    Linux实战教学笔记02:计算机系统硬件核心知识
    Linux实战教学笔记01:计算机硬件组成与基本原理
    从零开始学Python第八周:网络编程基础(socket)
  • 原文地址:https://www.cnblogs.com/zqlxtt/p/4771220.html
Copyright © 2011-2022 走看看