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;
}
这样就达到了重新连接并且不需要再次查询的目的。