Android Loader 异步加载详解一:基础概念

来源:互联网 发布:德军总部剧情知乎 编辑:程序博客网 时间:2024/06/05 09:16

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/70241844
本文出自【赵彦军的博客】

Android Loader 异步加载详解一:基础概念
Android Loader 异步加载详解二:探寻Loader内部机制

前言

Android 3.0 中引入了 Loader (加载器),支持轻松在 Activity 或片段中异步加载数据。 加载器具有以下特征:

  • 可用于每个 Activity 和 Fragment。
  • 支持异步加载数据。
  • 监控其数据源并在内容变化时传递新结果。
  • 在某一配置更改后重建加载器时,会自动重新连接上一个加载器的游标。 因此,它们无需重新查询其数据。

Loader API概述说明

如下是我们开发中常用的一些Loader相关接口:

Class/Interface Description LoaderManager 一个与Activity、Fragment关联的抽象类,用于管理一个或多个Loader实例。每个Activity或Fragment只能有一个LoaderManager,而一个LoaderManager可以有多个Loader。 LoaderManager.LoaderCallbacks 用于和LoaderManager交互的回调接口。譬如,可以使用onCreateLoader()创建一个新的Loader。 AsyncTaskLoader 抽象的Loader,提供一个AsyncTask继承实现。 CursorLoader AsyncTaskLoader的子类,用于向ContentResover请求返回一个Cursor。该类以标准游标查询实现了Loader协议,使用后台线程进行查询,使用这个Loader是从ContentProvider加载异步数据最好的方式。

启动一个 Loader

initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback)

可以看见上面的initLoader()方法有三个参数:

  • 第一个参数代表当前Loader的ID;
  • 第二个参数代表提供给Loader构造函数的参数,可选;
  • 第三个参数代表LoaderManager.LoaderCallbacks的回调实现;

上面initLoader()方法的调用确保了一个Loader被初始化和激活的状态,该方法的调运有如下两种结果:

  • 如果代表该Loader的ID已经存在,则后面创建的Loader将直接复用已经存在的;
  • 如果代表该Loader的ID不存在,initLoader()会触发LoaderManager.LoaderCallbacks回调的onCreateLoader()方法创建一个Loader;

可以看见通过initLoader()方法可以将LoaderManager.LoaderCallbacks实例与Loader进行关联,且当Loader的状态变化时就被回调。所以说,如果调用者正处于其开始状态并且被请求的Loader已经存在,且已产生了数据,那么系统会立即调用onLoadFinished()(在initLoader()调用期间),所以你必须考虑到这种情况的发生。

当然了,intiLoader()会返回一个创建的Loader,但是你不用获取它的引用,因为LoadeManager会自动管理该Loader的生命周期,你只用在它回调提供的生命周期方法中做自己数据逻辑的处理即可。

Loader 基类的源码分析

Loader 是最底层的代码逻辑封装,没有具体的业务实现的部分。这个有点像我们平时写的 BaseActivity 一样。现在我们来对这个基类的源码做一个简单的分析。

public class Loader<D> {    int mId;    OnLoadCompleteListener<D> mListener;    OnLoadCanceledListener<D> mOnLoadCanceledListener;    Context mContext;    boolean mStarted = false;    boolean mAbandoned = false;    boolean mReset = true;    boolean mContentChanged = false;    boolean mProcessingChange = false;    //数据源变化监听器(观察者模式),实现了ContentObserver类    public final class ForceLoadContentObserver extends ContentObserver {        public ForceLoadContentObserver() {            super(new Handler());        }        @Override        public boolean deliverSelfNotifications() {            return true;        }        @Override        public void onChange(boolean selfChange) {           //实质是调运Loader的forceLoad方法            onContentChanged();        }    } //Loader加载完成接口,当加载完成时Loader通知loaderManager,loaderManager再回调我们initLoader方法的callback    public interface OnLoadCompleteListener<D> {        /**         * Called on the thread that created the Loader when the load is complete.         *         * @param loader the loader that completed the load         * @param data the result of the load         */        public void onLoadComplete(Loader<D> loader, D data);    }    //LoaderManager中监听cancel,同上类似    public interface OnLoadCanceledListener<D> {        /**         * Called on the thread that created the Loader when the load is canceled.         *         * @param loader the loader that canceled the load         */        public void onLoadCanceled(Loader<D> loader);    }    //构造方法    public Loader(Context context) {        //mContext持有Application的Context,防止泄露内存等        mContext = context.getApplicationContext();    }    //加载完成时回调传递加载数据结果,实质是对OnLoadCompleteListener接口方法的封装    public void deliverResult(D data) {        if (mListener != null) {            mListener.onLoadComplete(this, data);        }    }   //类似同上,对OnLoadCanceledListener的方法的封装    public void deliverCancellation() {        if (mOnLoadCanceledListener != null) {            mOnLoadCanceledListener.onLoadCanceled(this);        }    }    public Context getContext() {        return mContext;    }    public int getId() {        return mId;    }    public void registerListener(int id, OnLoadCompleteListener<D> listener) {        if (mListener != null) {            throw new IllegalStateException("There is already a listener registered");        }        mListener = listener;        mId = id;    }    public void unregisterListener(OnLoadCompleteListener<D> listener) {        if (mListener == null) {            throw new IllegalStateException("No listener register");        }        if (mListener != listener) {            throw new IllegalArgumentException("Attempting to unregister the wrong listener");        }        mListener = null;    }    public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {        if (mOnLoadCanceledListener != null) {            throw new IllegalStateException("There is already a listener registered");        }        mOnLoadCanceledListener = listener;    }    public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {        if (mOnLoadCanceledListener == null) {            throw new IllegalStateException("No listener register");        }        if (mOnLoadCanceledListener != listener) {            throw new IllegalArgumentException("Attempting to unregister the wrong listener");        }        mOnLoadCanceledListener = null;    }    public boolean isStarted() {        return mStarted;    }    public boolean isAbandoned() {        return mAbandoned;    }    public boolean isReset() {        return mReset;    }    //开始加载数据时LoaderManager会调用该方法    //必须在 main thread 线程调用    public final void startLoading() {        mStarted = true;        mReset = false;        mAbandoned = false;        onStartLoading();    }    //真正开始加载数据的地方******空方法,子类实现!!!!!!    protected void onStartLoading() {    }    //取消Loader的方法    public boolean cancelLoad() {        return onCancelLoad();    }   //真正取消的地方******,子类实现!!!!!!return false表示取消失败(因为已完成或未开始)    protected boolean onCancelLoad() {        return false;    }    //强制重新Loader,放弃旧数据    public void forceLoad() {        onForceLoad();    }    //真正重新Loader的地方******空方法,子类实现!!!!!!    protected void onForceLoad() {    }    //停止 Loading ,具体实现交给子类    //必须在 main 线程调用    public void stopLoading() {        mStarted = false;        onStopLoading();    }    //空实现    protected void onStopLoading() {    }   //同上    public void abandon() {        mAbandoned = true;        onAbandon();    }   //同上    protected void onAbandon() {    }    //同上    public void reset() {        onReset();        mReset = true;        mStarted = false;        mAbandoned = false;        mContentChanged = false;        mProcessingChange = false;    }    //同上    protected void onReset() {    }    //Loader数据变化的一些标记处理    public boolean takeContentChanged() {        boolean res = mContentChanged;        mContentChanged = false;        mProcessingChange |= res;        return res;    }    public void commitContentChanged() {        mProcessingChange = false;    }    public void rollbackContentChanged() {        if (mProcessingChange) {            onContentChanged();        }    }    //上面ForceLoadContentObserver内部类的onChange方法调运    public void onContentChanged() {        if (mStarted) {            forceLoad();        } else {            // This loader has been stopped, so we don't want to load            // new data right now...  but keep track of it changing to            // refresh later if we start again.            mContentChanged = true;        }    }    //一些方便调试的方法    public String dataToString(D data) {        StringBuilder sb = new StringBuilder(64);        DebugUtils.buildShortClassTag(data, sb);        sb.append("}");        return sb.toString();    }    //一些方便调试的方法    @Override    public String toString() {        StringBuilder sb = new StringBuilder(64);        DebugUtils.buildShortClassTag(this, sb);        sb.append(" id=");        sb.append(mId);        sb.append("}");        return sb.toString();    }    //一些方便调试的方法    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {        writer.print(prefix); writer.print("mId="); writer.print(mId);                writer.print(" mListener="); writer.println(mListener);        if (mStarted || mContentChanged || mProcessingChange) {            writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);                    writer.print(" mContentChanged="); writer.print(mContentChanged);                    writer.print(" mProcessingChange="); writer.println(mProcessingChange);        }        if (mAbandoned || mReset) {            writer.print(prefix); writer.print("mAbandoned="); writer.print(mAbandoned);                    writer.print(" mReset="); writer.println(mReset);        }    }

通过上面粗略的分析可以发现,Loader基类无非也就是一个方法接口的定义类,组织预留了一些方法供LoaderManager去调运处理,同时需要子类实现其提供的一些onXXX方法,以便LoaderManager调运Loader的方法时可以触发Loader子类的实现逻辑。

AsyncTaskLoader 运用实例详解

上面我们说了 Loader 只是一个基类,那么要实现具体的业务类,必须有 子类继承Loader ,并且实现 Loader 里面的空方法。幸运的是,系统已经帮我们实现了一个子类 , 它就是 AsyncTaskLoader 。

AsyncTaskLoader 源码分析:

public abstract class AsyncTaskLoader<D> extends Loader<D> {    static final String TAG = "AsyncTaskLoader";    static final boolean DEBUG = false;    //LoadTask内部类是对AsyncTask的封装,实现了Runnable接口    final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {        private final CountDownLatch mDone = new CountDownLatch(1);        boolean waiting;        //AsyncTask的子线程中执行AsyncTaskLoader的onLoadInBackground方法!!!!重点        @Override        protected D doInBackground(Void... params) {            try {                D data = AsyncTaskLoader.this.onLoadInBackground();                //把执行结果数据D返回到UI线程                return data;            } catch (OperationCanceledException ex) {                if (!isCancelled()) {                    throw ex;                }                return null;            }        }        //AsyncTask子线程执行完毕后在主线程回调AsyncTaskLoader的dispatchOnLoadComplete方法        /* Runs on the UI thread */        @Override        protected void onPostExecute(D data) {            try {                AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);            } finally {                mDone.countDown();            }        }        /* Runs on the UI thread */        @Override        protected void onCancelled(D data) {            if (DEBUG) Log.v(TAG, this + " onCancelled");            try {                //取消AsyncTask时调用                AsyncTaskLoader.this.dispatchOnCancelled(this, data);            } finally {                mDone.countDown();            }        }        //Runnable的实现方法        /* 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() {            waiting = false;            AsyncTaskLoader.this.executePendingTask();        }        /* Used for testing purposes to wait for the task to complete. */        public void waitForLoader() {            try {                mDone.await();            } catch (InterruptedException e) {                // Ignore            }        }    }    private final Executor mExecutor;    volatile LoadTask mTask;    volatile LoadTask mCancellingTask;    long mUpdateThrottle;    long mLastLoadCompleteTime = -10000;    Handler mHandler;    //public构造方法     public AsyncTaskLoader(Context context) {        this(context, AsyncTask.THREAD_POOL_EXECUTOR);    }    /** {@hide}  无法被外部调运的构造方法 */    public AsyncTaskLoader(Context context, Executor executor) {        super(context);        mExecutor = executor;    }    public void setUpdateThrottle(long delayMS) {        mUpdateThrottle = delayMS;        if (delayMS != 0) {            mHandler = new Handler();        }    }    @Override    protected void onForceLoad() {        super.onForceLoad();        //取消当前的Loader执行        cancelLoad();        //新建task并执行        mTask = new LoadTask();        if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);        executePendingTask();    }    @Override    protected boolean onCancelLoad() {        if (DEBUG) Log.v(TAG, "onCancelLoad: mTask=" + mTask);        if (mTask != null) {            if (mCancellingTask != null) {                if (mTask.waiting) {                    mTask.waiting = false;                    mHandler.removeCallbacks(mTask);                 }                mTask = null;                return false;            } else if (mTask.waiting) {                // There is a task, but it is waiting for the time it should                // execute.  We can just toss it.                if (DEBUG) Log.v(TAG, "cancelLoad: task is waiting, dropping it");                mTask.waiting = false;                mHandler.removeCallbacks(mTask);                mTask = null;                return false;            } else {                boolean cancelled = mTask.cancel(false);                if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled);                if (cancelled) {                    mCancellingTask = mTask;                    cancelLoadInBackground();                }                mTask = null;                return cancelled;            }        }        return false;    }    /**     * Called if the task was canceled before it was completed.  Gives the class a chance     * to clean up post-cancellation and to properly dispose of the result.     *     * @param data The value that was returned by {@link #loadInBackground}, or null     * if the task threw {@link OperationCanceledException}.     */    public void onCanceled(D data) {    }    //LoadTask的Runnable方法run中执行    void executePendingTask() {        if (mCancellingTask == null && mTask != null) {            if (mTask.waiting) {                mTask.waiting = false;                mHandler.removeCallbacks(mTask);            }            if (mUpdateThrottle > 0) {                long now = SystemClock.uptimeMillis();                if (now < (mLastLoadCompleteTime+mUpdateThrottle)) {                    // Not yet time to do another load.                    mTask.waiting = true;                    mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);                    return;                }            }            //真正的触发执行AsyncTask方法            mTask.executeOnExecutor(mExecutor, (Void[]) null);        }    }    void dispatchOnCancelled(LoadTask task, D data) {        onCanceled(data);        if (mCancellingTask == task) {            rollbackContentChanged();            mLastLoadCompleteTime = SystemClock.uptimeMillis();            mCancellingTask = null;           //触发Loader的接口方法onLoadCanceled,在LoaderManager中实现            deliverCancellation();            executePendingTask();        }    }    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");                //触发Loader的接口方法onLoadComplete,在LoaderManager中实现                deliverResult(data);            }        }    }    //需要子类实现!!!!!在子线程中执行    public abstract D loadInBackground();   //LoadTask(AsyncTask的子线程中回调)中调运    protected D onLoadInBackground() {        return loadInBackground();    }    //LoadTask(AsyncTask的onCancelLoad中回调)调运    public void cancelLoadInBackground() {    }    public boolean isLoadInBackgroundCanceled() {        return mCancellingTask != null;    }    //锁标记处理    public void waitForLoader() {        LoadTask task = mTask;        if (task != null) {            task.waitForLoader();        }    }    @Override    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {        super.dump(prefix, fd, writer, args);        if (mTask != null) {            writer.print(prefix); writer.print("mTask="); writer.print(mTask);                    writer.print(" waiting="); writer.println(mTask.waiting);        }        if (mCancellingTask != null) {            writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask);                    writer.print(" waiting="); writer.println(mCancellingTask.waiting);        }        if (mUpdateThrottle != 0) {            writer.print(prefix); writer.print("mUpdateThrottle=");                    TimeUtils.formatDuration(mUpdateThrottle, writer);                    writer.print(" mLastLoadCompleteTime=");                    TimeUtils.formatDuration(mLastLoadCompleteTime,                            SystemClock.uptimeMillis(), writer);                    writer.println();        }    }}

可以看见上面继承Loader的AsyncTaskLoader其实质是提供了一个基于AsyncTask工作机制的Loader(子类LoadTask继承AsyncTask< Void, Void, D >,并且实现了Runable接口,功能十分强大。),但是不可直接用,因为其为abstract抽象类,所以我们需要继承实现它才可以使用,然而好在系统API已经帮我们提供了他现成的子类CursorLoader,但CursorLoader同时也限制了Loader的泛型数据为Cursor类型。当然了,我们如果想要Loader自己的类型数据那也很简单—继承实现AsyncTaskLoader即可,后面会给出例子的。

CursorLoader子类源码浅析

有了上面继承自Loader的抽象AsyncTaskLoader,接下来我们就来看看SDK为我们提供的抽象AsyncTaskLoader实现类CursorLoader,我们先来粗略看看该类的方法图,如下:

这里写图片描述

//CursorLoader 继承 AsyncTaskLoader , 数据类型为Cursor的Loader异步加载实现类public class CursorLoader extends AsyncTaskLoader<Cursor> {    //ContentObserver的子类ForceLoadContentObserver    final ForceLoadContentObserver mObserver;    Uri mUri;    String[] mProjection;    String mSelection;    String[] mSelectionArgs;    String mSortOrder;    Cursor mCursor;    CancellationSignal mCancellationSignal;    /* Runs on a worker thread */    //最核心的实现方法,在这里查询获取数据     @Override    public Cursor loadInBackground() {        synchronized (this) {            if (isLoadInBackgroundCanceled()) {                throw new OperationCanceledException();            }            mCancellationSignal = new CancellationSignal();        }        try {            //不过多解释,耗时的查询操作            Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,                    mSelectionArgs, mSortOrder, mCancellationSignal);            if (cursor != null) {                try {                    // Ensure the cursor window is filled.                    cursor.getCount();                    //给Cursor设置观察者;ContentProvider通知Cursor的观察者数据发生了改变,Cursor通知CursorLoader的观察者数据发生了改变,CursorLoader通过ContentProvider重新加载新的数据                    cursor.registerContentObserver(mObserver);                } catch (RuntimeException ex) {                    cursor.close();                    throw ex;                }            }            return cursor;        } finally {            synchronized (this) {                mCancellationSignal = null;            }        }    }    @Override    public void cancelLoadInBackground() {        super.cancelLoadInBackground();        synchronized (this) {            if (mCancellationSignal != null) {                mCancellationSignal.cancel();            }        }    }    /* Runs on the UI thread */    @Override    public void deliverResult(Cursor cursor) {        if (isReset()) {            // An async query came in while the loader is stopped            if (cursor != null) {                cursor.close();            }            return;        }        Cursor oldCursor = mCursor;        mCursor = cursor;        if (isStarted()) {            super.deliverResult(cursor);        }        if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {            oldCursor.close();        }    }    /**     * Creates an empty unspecified CursorLoader.  You must follow this with     * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc     * to specify the query to perform.     */    public CursorLoader(Context context) {        super(context);        mObserver = new ForceLoadContentObserver();    }    /**     * Creates a fully-specified CursorLoader.  See     * {@link ContentResolver#query(Uri, String[], String, String[], String)     * ContentResolver.query()} for documentation on the meaning of the     * parameters.  These will be passed as-is to that call.     */    public CursorLoader(Context context, Uri uri, String[] projection, String selection,            String[] selectionArgs, String sortOrder) {        super(context);        //新建一个当前类(Loader)的内部类对象,数据库变化时调运ForceLoadContentObserver的onChange方法,onChange调运Loader的onContentChanged方法,onContentChanged调运Loader的forceLoad方法        mObserver = new ForceLoadContentObserver();        mUri = uri;        mProjection = projection;        mSelection = selection;        mSelectionArgs = selectionArgs;        mSortOrder = sortOrder;    }    /**     * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks     * will be called on the UI thread. If a previous load has been completed and is still valid     * the result may be passed to the callbacks immediately.     *     * Must be called from the UI thread     */    @Override    protected void onStartLoading() {        if (mCursor != null) {            deliverResult(mCursor);        }        if (takeContentChanged() || mCursor == null) {            forceLoad();        }    }    /**     * Must be called from the UI thread     */    @Override    protected void onStopLoading() {        // Attempt to cancel the current load task if possible.        cancelLoad();    }    @Override    public void onCanceled(Cursor cursor) {        if (cursor != null && !cursor.isClosed()) {            cursor.close();        }    }    @Override    protected void onReset() {        super.onReset();        // Ensure the loader is stopped        onStopLoading();        if (mCursor != null && !mCursor.isClosed()) {            mCursor.close();        }        mCursor = null;    }    public Uri getUri() {        return mUri;    }    public void setUri(Uri uri) {        mUri = uri;    }    public String[] getProjection() {        return mProjection;    }    public void setProjection(String[] projection) {        mProjection = projection;    }    public String getSelection() {        return mSelection;    }    public void setSelection(String selection) {        mSelection = selection;    }    public String[] getSelectionArgs() {        return mSelectionArgs;    }    public void setSelectionArgs(String[] selectionArgs) {        mSelectionArgs = selectionArgs;    }    public String getSortOrder() {        return mSortOrder;    }    public void setSortOrder(String sortOrder) {        mSortOrder = sortOrder;    }    @Override    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {        super.dump(prefix, fd, writer, args);        writer.print(prefix); writer.print("mUri="); writer.println(mUri);        writer.print(prefix); writer.print("mProjection=");                writer.println(Arrays.toString(mProjection));        writer.print(prefix); writer.print("mSelection="); writer.println(mSelection);        writer.print(prefix); writer.print("mSelectionArgs=");                writer.println(Arrays.toString(mSelectionArgs));        writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder);        writer.print(prefix); writer.print("mCursor="); writer.println(mCursor);        writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged);    }}

可以发现,CursorLoader的封装大大简化了应用开发者代码的复杂度;它完全就是一个异步的数据库查询瑞士军刀,没有啥特别需要分析的地方,所以不再过多说明。

参考资料

官方文档

使用CursorLoader执行查询任务

Android应用Loaders全面详解及源码浅析

Android之Loader介绍

0 0
原创粉丝点击