Android异步加载神器Loader全解析
作者:网络转载 发布时间:[ 2015/10/9 13:13:33 ] 推荐标签:移动平台测试 移动测试
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 void forceLoad() {
onForceLoad();
}
/**
* Subclasses must implement this to take care of requests to {@link #forceLoad()}.
* This will always be called from the process's main thread.
*/
protected void onForceLoad() {
}
然后看看AsyncTaskLoader的几个主要方法:
//这边一目了然 asynacTaskLoader 里面 正好是有一个AsyncTask对象的!实现了runnabele接口
//注意着参数d 这个d是干嘛的,这个d是用来传递参数的一个泛型,可以是系统实现的loader里的cursor
//也可以是我们自己实现的loader里的list类型
final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
private final CountDownLatch mDone = new CountDownLatch(1);
// Set to true to indicate that the task has been posted to a handler for
// execution at a later time. Used to throttle updates.
boolean waiting;
/* Runs on a worker thread */
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
try {
//这个地方很明显了,他调用了自己的onLoadInBackGround方法
D data = AsyncTaskLoader.this.onLoadInBackground();
if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
return data;
} catch (OperationCanceledException ex) {
if (!isCancelled()) {
// onLoadInBackground threw a canceled exception spuriously.
// This is problematic because it means that the LoaderManager did not
// cancel the Loader itself and still expects to receive a result.
// Additionally, the Loader's own state will not have been updated to
// reflect the fact that the task was being canceled.
// So we treat this case as an unhandled exception.
throw ex;
}
if (DEBUG) Log.v(TAG, this + " <<< doInBackground (was canceled)", ex);
return null;
}
}
//后面还有很多代码 略过
}
//你看这里下面的2个函数 一看明白了 终task里调用的是这个抽象方法,那这个抽象方法
//是留给我们子类自己去实现的,我们在自定义loader的时候重要的是重写这个方法。
protected D onLoadInBackground() {
return loadInBackground();
}
public abstract D loadInBackground();
//你看这个地方 是当数据源发生变化的时候 会调用这个方法了,启动了我们的laodtask
//也是终调用子类 也是CursorLoader这样的子类的loadInBackground方法了
@Override
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
mTask = new LoadTask();
if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
executePendingTask();
}
相信到这里 大家一定能搞明白数据源变化的时候 是怎么一步步调用我们的loader里的回调方法的,那有人肯定要继续问当你这个方法调用完毕的时候 是怎么通知后updateUI呢,也是当你background方法结束以后是怎么调用的onLoadFinished方法的呢?
我们继续看AsyncTaskLoader这个类
//在那个asynctask里面 走完是肯定要走这个方法的 相信大家都能理解。
@Override
protected void onPostExecute(D data) {
if (DEBUG) Log.v(TAG, this + " onPostExecute");
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
mDone.countDown();
}
}
//实际上走的是这个方法。看26行-
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);
}
}
}
//这边一下看出来是调用的mListtenr的回调方法
public void deliverResult(D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
}
实际上这个Listener是在Loader这个基类里:
OnLoadCompleteListener<D> mListener;
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);
}
//并且通过这个注册
public void registerListener(int id, OnLoadCompleteListener<D> listener) {
if (mListener != null) {
throw new IllegalStateException("There is already a listener registered");
}
mListener = listener;
mId = id;
}
那好了 我们是要看一下 是在哪个地方调用的registerlistener这个方法 注册他的
//回到initLoader的这个方法 注意这个方法是在LoaderManger里面
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
LoaderInfo info = mLoaders.get(id);
if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
if (info == null) {
//下面的代码跳转到30行
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;
}
if (info.mHaveData && mStarted) {
// If the loader has already generated its data, report it now.
info.callOnLoadFinished(info.mLoader, info.mData);
}
return (Loader<D>)info.mLoader;
}
private LoaderInfo createAndInstallLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
try {
mCreatingLoader = true;
LoaderInfo info = createLoader(id, args, callback);
//这里跳转到43行
installLoader(info);
return info;
} finally {
mCreatingLoader = false;
}
}
void installLoader(LoaderInfo info) {
mLoaders.put(info.mId, info);
if (mStarted) {
//跳转到51行
info.start();
}
}
void 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;
}
mStarted = true;
if (DEBUG) Log.v(TAG, " Starting: " + this);
if (mLoader == null && mCallbacks != null) {
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
if (mLoader != null) {
if (mLoader.getClass().isMemberClass()
&& !Modifier.isStatic(mLoader.getClass().getModifiers())) {
throw new IllegalArgumentException(
"Object returned from onCreateLoader must not be a non-static inner member class: "
+ mLoader);
}
if (!mListenerRegistered) {
//是在这里注册的mloader里的回调了,注意这里的参数是this 也是loaderInfo这个类 注意这个类是loadermanger里的内部类了 再继续往下看
//我们前面说到 在asynctask里面终调用的是mLoader里的onLoadComplete方法 所以我们看看loaderInfo这个类里的这个方法做了什么看91行
mLoader.registerListener(mId, this);
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();
}
}
@Override
public void onLoadComplete(Loader<Object> loader, Object data) {
if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
if (mDestroyed) {
if (DEBUG) Log.v(TAG, " Ignoring load complete -- destroyed");
return;
}
if (mLoaders.get(mId) != this) {
// This data is not coming from the current active loader.
// We don't care about it.
if (DEBUG) Log.v(TAG, " Ignoring load complete -- not active");
return;
}
LoaderInfo pending = mPendingLoader;
if (pending != null) {
// There is a new request pending and we were just
// waiting for the old one to complete before starting
// it. So now it is time, switch over to the new loader.
if (DEBUG) Log.v(TAG, " Switching to pending loader: " + pending);
mPendingLoader = null;
mLoaders.put(mId, null);
destroy();
installLoader(pending);
return;
}
// Notify of the new data so the app can switch out the old data before
// we try to destroy it.
if (mData != data || !mHaveData) {
mData = data;
mHaveData = true;
if (mStarted) {
//继续往下 看第149行
callOnLoadFinished(loader, data);
}
}
//if (DEBUG) Log.v(TAG, " onLoadFinished returned: " + this);
// We have now given the application the new loader with its
// loaded data, so it should have stopped using the previous
// loader. If there is a previous loader on the inactive list,
// clean it up.
LoaderInfo info = mInactiveLoaders.get(mId);
if (info != null && info != this) {
info.mDeliveredData = false;
info.destroy();
mInactiveLoaders.remove(mId);
}
if (mHost != null && !hasRunningLoaders()) {
mHost.mFragmentManager.startPendingDeferredFragments();
}
}
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));
//到这里真相大白了,终callback是在这里调用的onLoadFinished方法也是我们经常重写的方法
mCallbacks.onLoadFinished(loader, data);
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
}
}
好,到这里 我们把Loader框架中的 数据传递 整个流程给摸清楚了。后我们再来看看 他的生命周期是如何管理的吧。
我们可以先看看activity的:
//看activity的onStart方法
protected void onStart() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
mCalled = true;
//继续看12行 这个地方mFragements 你理解成activity本身即可,不多做解释 这个地方要搞清楚 又是另外一块了 有兴趣的可以自行谷歌activity和fragment如何建立关系
mFragments.doLoaderStart();
getApplication().dispatchActivityStarted(this);
}
//这个函数很明显了 调用了manager的dostart函数
void doLoaderStart() {
if (mLoadersStarted) {
return;
}
mLoadersStarted = true;
if (mLoaderManager != null) {
//跳转到30行
mLoaderManager.doStart();
} else if (!mCheckedForLoaderManager) {
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
}
mCheckedForLoaderManager = true;
}
//------------------注意上面的代码都在activity里,下面的开始 都在LoaderManger类里了
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--) {
//跳转到50行
mLoaders.valueAt(i).start();
}
}
void 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;
}
mStarted = true;
if (DEBUG) Log.v(TAG, " Starting: " + this);
if (mLoader == null && mCallbacks != null) {
//原来onCreateLoader这个回调方法 是在这里调用的 怪不得谷歌说这个方法是必定会被执行并且只会被执行一次的方法!
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
if (mLoader != null) {
if (mLoader.getClass().isMemberClass()
&& !Modifier.isStatic(mLoader.getClass().getModifiers())) {
throw new IllegalArgumentException(
"Object returned from onCreateLoader must not be a non-static inner member class: "
+ mLoader);
}
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
//你看这里调用了startLoading方法 这个方法是属于mLoader的 跳转到88行
mLoader.startLoading();
}
}
//88- 98行是loader这个类里的
public final void startLoading() {
mStarted = true;
mReset = false;
mAbandoned = false;
onStartLoading();
}
//你看终是调用的这个方法,注意他是空方法 是交给子类去实现的,我们去看看cursorloader这个子类是怎么实现的吧。
protected void onStartLoading() {
}
//99- 112行 是cursorLoader这个类的代码
//你看这个地方 直接调用了forceload方法 这个方法大家前面肯定有印象 他终会启动那个asynctask 去执行background方法
//这也解释了 第一次我们的数据是怎么来的,比如说 假设我们的数据源还没有被更新的时候,为什么会自动去查找数据源 并返回数据
//到这里明白了,原来是activity的onStart函数为开端 一步步走到Loader的子类的onStartLoading方法里的,当然你如果觉得
//Loader不需要初始加载 只要在有变化的时候再加载 那这个方法你可以保持为空了。
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
//114-139行 为 http://developer.android.com/intl/zh-cn/reference/android/content/AsyncTaskLoader.html 这个里面 AppListLoader 的一段源码
//你看138行 也是直接调用的forceLoad 这样当我们的applist没有变化的时候 第一次也能显示出列表
/**
* Handles a request to start the Loader.
*/
@Override protected void onStartLoading() {
if (mApps != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mApps);
}
// Start watching for changes in the app data.
if (mPackageObserver == null) {
mPackageObserver = new PackageIntentReceiver(this);
}
// Has something interesting in the configuration changed since we
// last built the app list?
boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
if (takeContentChanged() || mApps == null || configChange) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
start流程 我们分析完毕了 后我们再看看stop流程吧 看完这个 其他生命周期 我们不分析了留给读者自己感兴趣的话自己分析试试看。
//我们来看看fragment的onDestroy方法 都做了什么
public void onDestroy() {
mCalled = true;
//Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
// + " mLoaderManager=" + mLoaderManager);
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
//跳转到16行
mLoaderManager.doDestroy();
}
}
//上面的代码 是在fragment里 下面的代码在loadermanger里
void doDestroy() {
if (!mRetaining) {
if (DEBUG) Log.v(TAG, "Destroying Active in " + this);
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).destroy();
}
mLoaders.clear();
}
if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
mInactiveLoaders.valueAt(i).destroy();
}
mInactiveLoaders.clear();
}
//下面这个destroy流程 可以清晰的看到很多东西 包括clear所有回调等
void destroy() {
if (DEBUG) Log.v(TAG, " Destroying: " + this);
mDestroyed = true;
boolean needReset = mDeliveredData;
mDeliveredData = false;
if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
if (DEBUG) Log.v(TAG, " Reseting: " + this);
String lastBecause = null;
if (mHost != null) {
lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
mHost.mFragmentManager.mNoTransactionsBecause = "onLoaderReset";
}
try {
mCallbacks.onLoaderReset(mLoader);
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
}
mCallbacks = null;
mData = null;
mHaveData = false;
if (mLoader != null) {
if (mListenerRegistered) {
mListenerRegistered = false;
mLoader.unregisterListener(this);
mLoader.unregisterOnLoadCanceledListener(this);
}
//在这调用了rest
mLoader.reset();
}
if (mPendingLoader != null) {
mPendingLoader.destroy();
}
}
//后我们来看看loader里的代码 能明白了 当fragement destroy的时候终的调用来到了子类的onReset方法
public void reset() {
onReset();
mReset = true;
mStarted = false;
mAbandoned = false;
mContentChanged = false;
mProcessingChange = false;
}
/**
* Subclasses must implement this to take care of resetting their loader,
* as per {@link #reset()}. This is not called by clients directly,
* but as a result of a call to {@link #reset()}.
* This will always be called from the process's main thread.
*/
protected void onReset() {
}
//这里是cURSORLOADER的代码了 你看这里关闭了cursor
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
//同样的 我们也能看到applistloader源码里面 也是在这个函数里清除了广播接收器。
//所以读到这里 我们知道 loader的强大了。你只需要搞清楚这些生命周期的函数的意义
//可以重写他们,至于什么时候调用 loader都帮你做好了 你只需要在里面实现你自己的逻辑即可!非常强大 非常好用
@Override protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (mApps != null) {
onReleaseResources(mApps);
mApps = null;
}
// Stop monitoring for changes.
if (mPackageObserver != null) {
getContext().unregisterReceiver(mPackageObserver);
mPackageObserver = null;
}
}
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
Android自动化测试框架有哪些?有什么用途?Android测试中最容易忽略的测试点有哪些?Android 手机自动化测试工具有哪几种?移动APP测试之android性能测试快速提升Android App 的代码覆盖率Android Unit Test 框架比较Android单元测试框架Robolectric3.0介绍(一)Android单元测试的整理在Android Studio中实现单元测试Android连接MySQL方法,测试成功关于Android MVP模式的思考Android 数据库管理?ActiveAndroid编写Android测试单元该做的和不该做的事Android阿里面试Java基础锦集在Android项目中使用Java8Java / Android 面试中所遇到的那些坑
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南