转载请标明出处: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的封装大大简化了应用开发者代码的复杂度;它完全就是一个异步的数据库查询瑞士军刀,没有啥特别需要分析的地方,所以不再过多说明。