Android Loader(二) CursorLoader
Android Loader(四) 自定义Loader从网络中获取文本数据
首先从加载数据的过程开始分析。
初始化Loader的方法是:getLoaderManager().initLoader(0, null, this);当这个方法调用之后,Loader就在后台进行初始化,以及数据加载的工作了。
先看一下LoaderManager代码,LoaderManager是一个抽象类,LoaderCallbacks是其内部类,LoaderCallbacks有onCreateLoader,onLoadFinished,onLoaderReset三个方法。
LoaderManager的关键抽象方法有:initLoader,restartLoader,destroyLoader,getLoader,他们都是通过LoaderManager的子类LoaderManagerImpl实现的。
class LoaderManagerImpl extends LoaderManager
LoaderManagerImpl的内部类LoaderInfo:
final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
Loader.OnLoadCanceledListener<Object> {
LoaderManagerImpl有2个全局变量SparseArray<LoaderInfo> mLoaders和SparseArray<LoaderInfo> mInactiveLoaders,mLoaders中存放着当前活动的Loader,mInactiveLoaders存放着以前运行的Loader。
下面从初始化Loader开始分析:
先看getLoaderManager().方法, 实际调用的是Activity的LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) ,返回一个LoaderManagerImpl,
LoaderManagerImpl的initLoader中的关键代码:
LoaderInfo info = mLoaders.get(id); if (info == null) { info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback); }createAndInstallLoader:
private LoaderInfo createAndInstallLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callback) { try { mCreatingLoader = true; LoaderInfo info = createLoader(id, args, callback); installLoader(info); return info; } finally { mCreatingLoader = false; } }createLoader:
private LoaderInfo createLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callback) { LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks<Object>)callback); Loader<Object> loader = callback.onCreateLoader(id, args); info.mLoader = (Loader<Object>)loader; return info; }可以看到, LoaderInfo通过 createLoader实例化,并且在createLoader中,调用LoaderCallbacks的onCreateLoader创建Loader,onCreateLoader在实现了LoaderCallbacks的Fragment或Activity中实现,这样就完成了Loader的创建。再看 installLoader方法:
void installLoader(LoaderInfo info) { mLoaders.put(info.mId, info); if (mStarted) { info.start(); } }mStarted的值为true,赋值过程如下:
LoaderManagerImpl构造方法:
LoaderManagerImpl(String who, Activity activity, boolean started) { mWho = who; mActivity = activity; mStarted = started; }这是在Activity的 getLoaderManager中调用的:
lm = new LoaderManagerImpl(who, this, started);started的值在Fragment的getLoaderManager调用中赋值
mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, true);这个 mLoadersStarted是全局变量,在Fragment的onStart方法中赋值
Fragment.onStart():
protected void onStart() { ...... if (!mLoadersStarted) { mLoadersStarted = true; if (mLoaderManager != null) { mLoaderManager.doStart(); } else if (!mCheckedForLoaderManager) { mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false); } mCheckedForLoaderManager = true; } getApplication().dispatchActivityStarted(this); }再回到installLoader方法,info.start()被调用,start方法:
...... mStarted = true; ...... if (!mListenerRegistered) { mLoader.registerListener(mId, this); mLoader.registerOnLoadCanceledListener(this); mListenerRegistered = true; } mLoader.startLoading();Loader.startLoading():
public final void startLoading() { mStarted = true; mReset = false; mAbandoned = false; onStartLoading(); }
查看Loader类的说明:
Subclasses generally must implement at least onStartLoading(),onStopLoading(), onForceLoad(), onReset()
onStartLoading方法是需要Loader的子类重写的,以CursorLoader为例:
@Override protected void onStartLoading() { if (mCursor != null) { deliverResult(mCursor); } if (takeContentChanged() || mCursor == null) { forceLoad(); } }deliverResult():
public void deliverResult(D data) { if (mListener != null) { mListener.onLoadComplete(this, data); } }从以上代码可以看出, 如果mCursor不为空,则说明数据查询已经结束, 直接调用onLoadComplete, mListener对象是 Loader内部接口 OnLoadCompleteListener的实例:
OnLoadCompleteListener<D> mListener; public interface OnLoadCompleteListener<D> { public void onLoadComplete(Loader<D> loader, D data); }
onLoadComplete中调用了 callOnLoadFinished方法,callOnLoadFinished中调用了 onLoadFinished:
mCallbacks.onLoadFinished(loader, data);
onLoadFinished也是需要重写的方法,一般在使用CursorLoader的类中, LoaderCallbacks的onLoadFinished方法都这样实现:
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { mAdapter.swapCursor(data); }再来看onStartLoading中的另外一个判断语句:
if (takeContentChanged() || mCursor == null) { forceLoad(); }forceLoad:
public void forceLoad() { onForceLoad(); }onForceLoad在CursorLoader的父类 AsyncTaskLoader中已经重写,一般自定义的Loader不直接继承Loader,而是继承 AsyncTaskLoader,CursorLoader也是如此。
@Override protected void onForceLoad() { super.onForceLoad(); cancelLoad(); mTask = new LoadTask(); if (DEBUG) Slog.v(TAG, "Preparing load: mTask=" + mTask); executePendingTask(); }Loader.cancelLoad:
public boolean cancelLoad() { return onCancelLoad(); }AsyncTaskLoader.onCancelLoad:
@Override protected boolean onCancelLoad() { if (DEBUG) Slog.v(TAG, "onCancelLoad: mTask=" + mTask); if (mTask != null) { if (mCancellingTask != null) { // There was a pending task already waiting for a previous // one being canceled; just drop it. if (DEBUG) Slog.v(TAG, "cancelLoad: still waiting for cancelled task; dropping next"); 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) Slog.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) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled); if (cancelled) { mCancellingTask = mTask; cancelLoadInBackground(); } mTask = null; return cancelled; } } return false; }这个方法的作用是取消之前没有或者正在执行的 mTask, mTask是一个AsyncTask。
之前提到,Loader的子类必须实现的方法之一是onStopLoading,CursorLoader中的onStopLoading实际上就间接调用了onCancelLoad:
@Override protected void onStopLoading() { // Attempt to cancel the current load task if possible. cancelLoad(); }继续看onForceLoad的代码:
mTask = new LoadTask(); executePendingTask();
LoadTask就是个AsyncTask, LoadTask的doInBackground中:
D data = AsyncTaskLoader.this.onLoadInBackground(); return data;
protected D onLoadInBackground() { return loadInBackground(); }Loader异步的特性就是通过这个AsyncTask实现的,executePendingTask方法启动这个task,Loader的子类重写LoadInBackground完成数据的异步加载。这个方法在CursorLoader的实现如下:
@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.registerContentObserver(mObserver); } catch (RuntimeException ex) { cursor.close(); throw ex; } } return cursor; } finally { synchronized (this) { mCancellationSignal = null; } } }在这段代码中,对指定URI的查询结果放入Cursor对象,然后在 LoadTask的onPostExecute中处理:
@Override protected void onPostExecute(D data) { if (DEBUG) Slog.v(TAG, this + " onPostExecute"); try { AsyncTaskLoader.this.dispatchOnLoadComplete(this, data); } finally { mDone.countDown(); } }dispatchOnLoadComplete中,调用了deliverResult,这样,在onLoadFinished中就能获取Cursor数据。
以上是一个Loader从创建到初始化到加载并传递数据的过程。
Loader的onReset也是需要子类重写的方法,AsyncTaskLoader没有实现这个方法,CursorLoader的实现如下:
@Override protected void onReset() { super.onReset(); // Ensure the loader is stopped onStopLoading(); if (mCursor != null && !mCursor.isClosed()) { mCursor.close(); } mCursor = null; }onReset方法做了2件事,调用onStopLoading和关闭cursor, onRest方法在Loader的reset中被调用,而reset在LoaderManagerImpl的destroy() 调用, destroy()这个方法是在Loader需要销毁时调用的,所以onReset中应该实现停止加载数据和释放资源的逻辑。
Loader可以探测到数据源的变化并且自动加载,这个特性,用CursorLoader的代码来解读:
先看CursorLoader的构造方法:
public CursorLoader(Context context) { super(context); mObserver = new ForceLoadContentObserver(); }ForceLoadContentObserver是Loader的内部类,它是ContentObserver的子类,在Cursor的loadInBackground() 中,向这个Observer进行了注册:
cursor.registerContentObserver(mObserver);这里使用了观察者模式, ForceLoadContentObserver是Obeserver,Cursor是Subject,当Cursor内容改变时,ForceLoadContentObserver的onChange方法会被调用,进而调用onContentChanged():
@Override public void onChange(boolean selfChange) { onContentChanged(); }
onContentChanged:
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; } }内部调用了 forceLoad对数据进行重新加载,所以CursorLoader在数据源发生变化时可以重新加载数据。
最后来看一下为什么CursorLoader可以在configuration change时重新连接Cursor:
在 configuration change时,Activity会被销毁并重建,不论Fragment还是Activity都会调用onStart这个回调 ,onStart中的 mLoaderManager.doStart(),调用了LoaderManager的doStart();
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 for (int i = mLoaders.size()-1; i >= 0; i--) { mLoaders.valueAt(i).start(); } }
mLoader中的Loader是在 installLoader方法中添加的:mLoaders.put(info.mId, info);
for循环中,从 mLoaders中获取正在运行的Loader,重新调用它们的 start方法,在start中有以下判断:
if (mRetaining && mRetainingStarted) { // Our owner is started, but we were being retained from a // previous instance in the started state... so there is really // nothing to do here, since the loaders are still started. mStarted = true; return; } if (mStarted) { // If loader already started, don't restart. return; }
这样就达到了重新连接并且不需要再次查询的目的。