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相关接口:
启动一个 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介绍
- Android Loader 异步加载详解一:基础概念
- Android Loader 异步加载详解二:探寻Loader内部机制
- android---(Loader异步加载)
- Android图片异步加载之Universal-Image-Loader(一)
- Android异步加载数据---Loader
- Android Loader 异步加载数据
- Android异步加载数据--Loader
- Android—Loader异步加载
- Universal-Image-Loader异步加载图片详解
- android 加载器loader详解
- android--加载器loader详解
- android 加载器loader详解
- Android-Universal-Image-Loader 异步加载图片
- Android异步加载器Loader的使用
- Android Loader机制,实现异步加载数据
- Android 异步加载神器Loader全解析
- Android基础--Android Loader详解
- 【Android基础笔记17】Loader异步装载
- AFNetworking(v3.0+)框架学习总结(二内部逻辑处理过程)
- 【类反射】反射示例(模拟Instanceof的功能)
- Linux系统下配置Java环境
- Android .9图片
- Oracle 触发器更新本表数据
- Android Loader 异步加载详解一:基础概念
- Linux环境下配置虚拟主机域名
- iOS开发-UIWindow的用法-创建悬浮按钮
- 快速阅读——套路
- 数据结构之并查集
- C++ STL中容器的使用全面总结
- CSS3 background-size图片自适应
- Phoenix 配置
- Linux常用命令