本文转载地址:Android应用Loaders全面详解及源码浅析
本文是对上述内容的总结。
流程
当需要使用loader时,需要获取activity或fragment中的loaderManager并启动loader。
getLoaderManager().initLoader(1, null, new LoaderManager.LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return null;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
});
进入getLoaderManager中,一直到最后
LoaderManagerImpl getLoaderManagerImpl() {
if (mLoaderManager != null) {
return mLoaderManager;
}
mCheckedForLoaderManager = true;
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
return mLoaderManager;
}
可以发现每个activity都只会有一个LoaderManager,该LoaderManager通过getLoaderManager方法创建。
LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
if (mAllLoaderManagers == null) {
mAllLoaderManagers = new ArrayMap<String, LoaderManager>();
}
LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
if (lm == null) {
if (create) {
lm = new LoaderManagerImpl(who, this, started);
mAllLoaderManagers.put(who, lm);
}
} else {
lm.updateHostController(this);
}
return lm;
}
传入三个参数,其中who为在该LoaderManager在mAllLoaderManagers列表中对应的key,create为true时创建LoaderManager。
获取LoaderManager后,需要调用其initLoader方法。
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
//从列表中取出对应id的loader。loaderInfo中封装了一个loader
LoaderInfo info = mLoaders.get(id);
if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
//如果为空则创建loader
if (info == null) {
// Loader doesn't already exist; create.
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
if (DEBUG) Log.v(TAG, " Created new loader " + info);
} else {
if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
//已有数据,调用callOnLoadFinished方法
if (info.mHaveData && mStarted) {
info.callOnLoadFinished(info.mLoader, info.mData);
}
return (Loader<D>)info.mLoader;
}
//创建和初始化loader
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;
}
}
//创建loader
private LoaderInfo createLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
//关键点,获取在onCreateLoader方法中,用户创建的Loader
Loader<Object> loader = callback.onCreateLoader(id, args);
info.mLoader = (Loader<Object>)loader;
return info;
}
void installLoader(LoaderInfo info) {
//放入列表中
mLoaders.put(info.mId, info);
if (mStarted) {
info.start();
}
}
在initLoader中主要是创建了一个Loader(该Loader是在onCreateLoader中创建的Loader),并用LoaderInfo进行了封装。在方法的最后调用了LoaderInfo的start()方法。
void start() {
。。。
mStarted = true;
if (mLoader == null && mCallbacks != null) {
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
if (mLoader != null) {
。。。
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();
}
}
该方法主要是注册监听事件及调用Loader的StartLoading()方法,实际上调用了Loader的onStartLoading()方法,该方法内部为空,在自定义Loader时实现。
以CursorLoader为例,在CursorLoader中找到onStartLoading()方法:
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
初始化时,mCursor为空,进入forceLoad()方法中:
public void forceLoad() {
onForceLoad();
}
再进入onForceLoad()中,发现方法为空,其具体实现在AsyncTaskLoader中:
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
//新建task
mTask = new LoadTask();
if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
executePendingTask();
}
进入executePendingTask()中:
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.
if (DEBUG) Log.v(TAG, "Waiting until "
+ (mLastLoadCompleteTime+mUpdateThrottle)
+ " to execute: " + mTask);
mTask.waiting = true;
mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
return;
}
}
if (DEBUG) Log.v(TAG, "Executing: " + mTask);
mTask.executeOnExecutor(mExecutor, (Void[]) null);
}
}
executePendingTask首先判断了任务是否正在运行,如果正在运行则停止,之后又判断是否设置了更新时间,最后就是真正的触发执行AsyncTask方法executeOnExecutor。该方法会执行对应的任务mTask。
接着进入LoaderTask的都InBackground中:
protected D doInBackground(Void... params) {
if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
try {
D data = AsyncTaskLoader.this.onLoadInBackground();
if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
return data;
} catch (OperationCanceledException ex) {
if (!isCancelled()) {
throw ex;
}
if (DEBUG) Log.v(TAG, this + " <<< doInBackground (was canceled)", ex);
return null;
}
}
在该方法中最关键是调用了onLoadInBackground(),在onLoadInBackground()方法中调用了loadInBackground(),该方法在自定义Loader中实现去获取相应的数据。
在CursorLoader中:
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;
}
}
}
可以看到,在CursorLoader中,获取了相应cursor。即从对应的数据库中获取到了数据。获取数据后将数据返回。
@Override
protected void onPostExecute(D data) {
if (DEBUG) Log.v(TAG, this + " onPostExecute");
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
mDone.countDown();
}
}
进入dispatchOnLoadComplete():
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");
deliverResult(data);
}
}
}
在其中进行了一系列操作,关键是调用了deliverResult方法。该方法需要在子类中被实现。
CursorLoader中的delverResult:
public void deliverResult(Cursor cursor) {
if (isReset()) {
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();
}
}
public void deliverResult(D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
}
onLoadComplete的具体实现在LoaderInfo类中:
@Override
public void onLoadComplete(Loader<Object> loader, Object data) {
。。。
if (mData != data || !mHaveData) {
mData = data;
mHaveData = true;
if (mStarted) {
callOnLoadFinished(loader, data);
}
}
。。
}
取关键部分的代码,可以发现调用了callOnLoadFinished方法:
void callOnLoadFinished(Loader<Object> loader, Object data) {
if (mCallbacks != null) {
String lastBecause = null;
if (mHost != null) {
lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
}
try {
if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": "
+ loader.dataToString(data));
**mCallbacks.onLoadFinished(loader, data);**
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
}
}
可以看见,在该方法中调用了onLoadFinished方法。在onLoadFinished方法中,根据新获得的数据更新容器。至此,执行initLoader的过程结束,相应容器获得数据并进行相应操作。
CursorLoader在loadInBackground中注册了一各观察者cursor.registerContentObserver(mObserver);其中mObserver为Loader定义的ForceLoadContentObserver类,该类继承自ContentObserver,因此当数据库中数据发生变化后,会调用ForceLoadContentObserver的onChange方法。
@Override
public void onChange(boolean selfChange) {
onContentChanged();
}
public void onContentChanged() {
if (mStarted) {
**forceLoad();**
} else {
mContentChanged = true;
}
}
每当数据库中发生变化,都会调用forceLoad方法,每当调用forceLoad方法将重新执行上述操作。
小结
1.当执行initLoader方法后,首先会调用对应Loader的onStartLoading()方法,该方法中需要调用forceLoad()方法。
2.forceLoad方法会开启一个线程用于执行对应的任务,即在LoadTask中的doInBackground执行对应Loader的loadInBackground方法,在该方法中实现数据的获取。
3.获取数据后将调用子类的deliverResult方法,该方法中更新数据并最终调用回调方法onLoadComplete,从而执行onLoadFinished,最终在onLoadFinished中实现容器的数据更新。
4.当数据发生变化时,只需调用forceLoad即可再次执行上述操作。如在cursorLoader中通过注册观察者,当数据库中发生变化,执行对应的onChange方法,从而调用forceLoad方法进行更新。
题外话:
看源码是一件很痛苦的事情,Android应用Loaders全面详解及源码浅析看了两天也只是似懂非懂的样子,后来干脆直接从流程来看源码,抛弃一些看的不是很明白的部分,只看整个流程。虽然没把所有的源码看懂,但至少了解了大概的实现方式。因此本篇文章只是对Loader进行简单的认识,想看详细的可以参考Android应用Loaders全面详解及源码浅析