LoaderManager使用详解(五)---LoaderManager在Activity/Fragment中的使用分析

来源:互联网 发布:node n 切换版本 编辑:程序博客网 时间:2024/05/29 14:17

LoaderManager

外部接口initLoader:起始
1.     public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
2.         if (mCreatingLoader) {
3.             throw new IllegalStateException("Called while creating a loader");
4.         }
5.
6.         LoaderInfo info = mLoaders.get(id);
7.
8.         if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
9.
10.         if (info == null) {
11.             // Loader doesn't already exist; create.
12.             info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
13.             if (DEBUG) Log.v(TAG, "  Created new loader " + info);
14.         } else {
15.             if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
16.             info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
17.         }
18.
19.         if (info.mHaveData && mStarted) {
20.             // If the loader has already generated its data, report it now.
21.             info.callOnLoadFinished(info.mLoader, info.mData);
22.         }
23.
24.         return (Loader<D>)info.mLoader;
25.     }

1.mCreatingLoader代表当前LoaderManager正处于创建Loader的状态,这个时候进入initLoader属于冲突。
2.LoaderInfo为LoaderManager内部保存Loader信息的一个类,mLoaders保存了此LoaderManager加载过的Loader,需要注意:一个ID对应一个Loader。
3.info获取不到,说明这次是一个新的Loader进来,需要通过createAndInstallLoader进行创建和安装,参数即为initLoader的参数。
4.如果获取到了info,说明这是一个已经存在过的Loader,只需要重新对callback回调进行重新赋值即可。
5.若获取到的Loader已经开始,并且产生了有效数据,则执行LoaderInfo的callOnLoadFinished方法上报数据。
6.最终返回LoaderInfo中的Loader信息。

LoaderInfo声明了Loader.OnLoadCompleteListener接口,并且保存了一个Loader的几乎所有信息和状态。


LoaderInfo的构造函数
1. public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
2.     mId = id;
3.     mArgs = args;
4.     mCallbacks = callbacks;
5. }


createAndInstallLoader
1. private LoaderInfo createAndInstallLoader(int id, Bundle args,
2.          LoaderManager.LoaderCallbacks<Object> callback) {
3.      try {
4.          mCreatingLoader = true;
5.          LoaderInfo info = createLoader(id, args, callback);
6.          installLoader(info);
7.          return info;
8.      } finally {
9.          mCreatingLoader = false;
10.      }
11. }


createLoader
1. private LoaderInfo createLoader(int id, Bundle args,
2.         LoaderManager.LoaderCallbacks<Object> callback) {
3.     LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
4.     Loader<Object> loader = callback.onCreateLoader(id, args);
5.     info.mLoader = (Loader<Object>)loader;
6.     return info;
7. }


通过调用callback的onCreateLoader接口创建Loader。这样一个描述Loader的LoaderInfo就被成功创建了。完成了创建后,接下来是安装。

installLoader
1.void installLoader(LoaderInfo info) {
2.    mLoaders.put(info.mId, info);
3.    if (mStarted) {
4.        // The activity will start all existing loaders in it's onStart(),
5.        // so only start them here if we're past that point of the activitiy's
6.        // life cycle
7.        info.start();
8.    }
9.}

1.将新的Loader装进mLoaders保存,凡是通过此LoaderManager管理过的Loader都会有记录的
2.即使是在Fragment中使用LoaderManager,其获取方式也是通过Fragment附属的Activity获取,而mStarted状态量与Activity的生命周期onStart/onStop有关。稍后做详细分析。
3.若Activity的生命周期处于onStart和onStop中,则开启Loader。

LoaderInfo的start()
1. void start() {
2.     if (mRetaining && mRetainingStarted) {
3.         // Our owner is started, but we were being retained from a
4.         // previous instance in the started state...  so there is really
5.         // nothing to do here, since the loaders are still started.
6.         mStarted = true;
7.         return;
8.     }
9.
10.     if (mStarted) {
11.         // If loader already started, don't restart.
12.         return;
13.     }
14.
15.     mStarted = true;
16.
17.     if (DEBUG) Log.v(TAG, "  Starting: " + this);
18.     if (mLoader == null && mCallbacks != null) {
19.         mLoader = mCallbacks.onCreateLoader(mId, mArgs);
20.     }
21.     if (mLoader != null) {
22.                 if (mLoader.getClass().isMemberClass()
23.                         && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
24.                     throw new IllegalArgumentException(
25.                             "Object returned from onCreateLoader must not be a non-static inner member class: "
26.                             + mLoader);
27.                 }
28.                 if (!mListenerRegistered) {
29.                     mLoader.registerListener(mId, this);
30.                     mListenerRegistered = true;
31.                 }
32.                 mLoader.startLoading();
33.             }
34.         }

1.如果Loader还处于上一个的开始状态中,就不做任何事情
2.如果已经开始了,不要重启
3.若Loader为null,则调用callback的接口再创建一个
4.注册Loader的监听器,以id为唯一标识
5.启动Loader

Loader的startLoading()
1. public final void startLoading() {
2.     mStarted = true;
3.     mReset = false;
4.     mAbandoned = false;
5.     onStartLoading();
6. }


会启动Loader的onStartLoading,如果是复写的Loader或者AsyncTaskLoader,就是执行到了这里,是Loader在构造后执行的第一道工序。

关于结果数据的Loader回调

在LoaderInfo中给Loader注册了回调,回调就是LoaderInfo本身。下边以AsyncTaskLoader为例进行分析。

AsyncTaskLoader继承于Loader,同时其内部完成了一个AsyncTask。AsyncTaskLoader的抽象接口
1.public abstract D loadInBackground();


其实就是运行在其内部的AsyncTask中的doInBackground。


PS: 继承于AsyncTaskLoader的Loader不会在构造后自动启动,需要覆写onStartLoading中执行forceLoad,此Loader才会在onStartLoading的生命周期时正常启动。

在其内部的AsyncTask完成后会在onPostExecute中调用AsyncTaskLoader的dispatchOnLoadComplete
1. void dispatchOnLoadComplete(LoadTask task, D data) {
2.     if (mTask != task) {
3.         if (DEBUG) Slog.v(TAG, "Load complete of old task, trying to cancel");
4.         dispatchOnCancelled(task, data);
5.     } else {
6.         if (isAbandoned()) {
7.             // This cursor has been abandoned; just cancel the new data.
8.             onCanceled(data);
9.         } else {
10.             commitContentChanged();
11.             mLastLoadCompleteTime = SystemClock.uptimeMillis();
12.             mTask = null;
13.             if (DEBUG) Slog.v(TAG, "Delivering result");
14.             deliverResult(data);
15.         }
16.     }
17. }

•如果完成的是旧任务,则取消掉

•isAbandoned是Loader的方法,通过主动调用Loader的abandon()方法可以放弃这个Loader的执行结果,如果此Loader已经被放弃,那么调用
1.  public void onCanceled(D data)


处理被去掉的数据,AsyncTaskLoader中没有做任何处理,留给继承者自行决定是否处理


•排除以上两种异常情况,正常时会调用Loader的deliverResult处理数据结果。
1.public void deliverResult(D data) {
2.        if (mListener != null) {
3.             mListener.onLoadComplete(this, data);
4.         }
5.}


之前分析过的LoaderInfo为自己的Loader注册了监听器,实现是自己,这下子数据就传递回去了:
1.  @Override public void onLoadComplete(Loader<Object> loader, Object data) {
2.     if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
3.
4.     if (mDestroyed) {
5.         if (DEBUG) Log.v(TAG, "  Ignoring load complete -- destroyed");
6.         return;
7.     }
8.
9.     if (mLoaders.get(mId) != this) {
10.         // This data is not coming from the current active loader.
11.         // We don't care about it.
12.         if (DEBUG) Log.v(TAG, "  Ignoring load complete -- not active");
13.         return;
14.     }
15.
16.     LoaderInfo pending = mPendingLoader;
17.     if (pending != null) {
18.         // There is a new request pending and we were just
19.         // waiting for the old one to complete before starting
20.         // it.  So now it is time, switch over to the new loader.
21.         if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
22.         mPendingLoader = null;
23.         mLoaders.put(mId, null);
24.         destroy();
25.         installLoader(pending);
26.         return;
27.     }
28.
29.     // Notify of the new data so the app can switch out the old data before
30.     // we try to destroy it.
31.     if (mData != data || !mHaveData) {
32.         mData = data;
33.         mHaveData = true;
34.         if (mStarted) {
35.             callOnLoadFinished(loader, data);
36.         }
37.     }
38.
39.     //if (DEBUG) Log.v(TAG, "  onLoadFinished returned: " + this);
40.
41.     // We have now given the application the new loader with its
42.     // loaded data, so it should have stopped using the previous
43.     // loader.  If there is a previous loader on the inactive list,
44.     // clean it up.
45.     LoaderInfo info = mInactiveLoaders.get(mId);
46.     if (info != null && info != this) {
47.         info.mDeliveredData = false;
48.         info.destroy();
49.         mInactiveLoaders.remove(mId);
50.     }
51.
52.     if (mActivity != null && !hasRunningLoaders()) {
53.         mActivity.mFragments.startPendingDeferredFragments();
54.     }
55. }

1.若LoaderInfo已经通过destroy()进行过销毁,则不处理任何事情
2.若回传的Loader与LoaderInfo描述的并不是一个,也不做任何处理
3.mPendingLoader在LoaderManager的restartLoader中被赋值。若之前LoaderInfo中的Loader已经开始了,那么会新建一个Loader给LoaderInfo作为等待,在这里,如果有等待着的Loader则直接废弃之前的Loader,把等待的Loader扶正。同样的,返回的数据也就不进行任何处理了。
4.如果是新数据,且Loader生命周期正常,则调用callOnLoadFinished对数据进行处理,这里调用了回调函数callback中的onLoadFinished
5.mInactiveLoaders用来保存不活跃的Loader,如果Loader不活跃了,LoaderManager并不会马上删除它,而是将其保存在mInactiveLoaders中,直到此Loader的新数据来了,就将其销毁掉。

LoaderManager与生命周期

Activity和Fragment都拥有getLoaderManager的方法,其实Fragment的getLoaderManager去获取的就是Activity所管理的众多LoaderManager之一。

Who标签

先来看一下Activity的getLoaderManager方法:
1.     LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
2.         if (mAllLoaderManagers == null) {
3.             mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>();
4.         }
5.         LoaderManagerImpl lm = mAllLoaderManagers.get(who);
6.         if (lm == null) {
7.             if (create) {
8.                 lm = new LoaderManagerImpl(who, this, started);
9.                 mAllLoaderManagers.put(who, lm);
10.             }
11.         } else {
12.             lm.updateActivity(this);
13.         }
14.         return lm;
15.     }


mAllLoaderManagers保存着一个Activity所拥有的所有LoaderManager,其key为String类型的who变量。若从Activity调用getLoaderManager,那么所得LoaderManager的who标签为(root):
1.     public LoaderManager getLoaderManager() {
2.         if (mLoaderManager != null) {
3.             return mLoaderManager;
4.         }
5.         mCheckedForLoaderManager = true;
6.         mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
7.         return mLoaderManager;
8.     }


若从Fragment中使用getLoaderManager,则所得LoaderManager的who标签会根据Fragment的层级不同而不同,在Activity中处于最顶级的Fragment的who标签为:
1.android:fragment:X


X为序号。

而属于Fragment的Fragment所活的的LoaderManager who标签就成为了:
1.android:fragment:X:Y


甚至更大的深度。

LoaderManager状态量mLoadersStarted

在开篇分析的时候分析过LoaderManager内部保存了一个mStarted状态,很多操作会根据这个状态做不同处理。通过上边的分析也能看出,Fragment中获取LoaderManager最终是通过Activity获取的,在LoaderManager构造时,就将一个状态量mLoadersStarted传递了进去,这个状态量交给LoaderManager自行管理。

而无论是Fragment还是Activity,都有mLoadersStarted这样一个状态量,在onStart生命周期后为true,onStop后为false。所以在onStart生命周期后做initLoader操作就会使Loader一经初始化就开始运行了。

Fragment和Activity的生命周期

Fragment和Activity能够对LoaderManager产生影响的生命周期是一样的。

onStart

系统在onStart阶段会获取LoaderManager,如果成功获取,则调用LoaderManager的doStart(),这里需要特别说明的是,虽然所有LoaderManager都是保存在Activity中,但是在Activity的onStart生命周期其也只是会获取属于自己的(root)标签LoaderManager,而并不是将所有保存在mAllLoaderManagers里的Manager全部遍历一遍。

onStop(performStop)

处于onStop生命周期,但是系统内部是通过performStop调用的。在这里,同样会获取属于自己的LoaderManager,如果Activity是因为配置改变出发的onStop(旋转屏幕),则调用LoaderManager的doRetain()接口,如果不是,就调用LoaderManager的doStop()接口。

onDestroy(performDestroy)

调用LoaderManager的doDestroy()接口销毁LoaderManager。

LoaderManager的生命周期

因为LoaderManager与Fragment/Activity的生命周期紧密相连,所以想要用好LoaderManager就必须了解其自身的生命周期,这样就能把握数据的完整变化规律了。

正常的从出生到销毁:
1.doStart() -> doReportStart() -> doStop() -> doDestroy()


Activity配置发生变化:
1.doStart() -> doRetain() -> finishRetain() -> doReportStart() -> doStart() -> doStop() -> doDestroy()


Fragment在onDestroyView()之后还会执行LoaderManager的doReportNextStart(), 即:
1.doStart() -> doRetain() -> doReportNextStart() -> finishRetain() -> doReportStart() -> doStart() -> doStop() -> doDestroy()


1.doStart()会将LoaderManager中保存的所有Loader都启动。最终是运行每一个Loader的onStartLoading()方法。只要是通过initLoader使用过的Loader都会记录在LoaderManager的mLoaders中,那么问题来了:


怎样在Fragment/Activity不销毁的前提下从LoaderManager中移除某个使用过的Loader呢?

答案就是使用LoaderManager的接口去除指定ID的Loader:
1. public void destroyLoader(int id)


这样就能在mLoaders中移除掉了,下次onStart的时候就没有这个Loader什么事了。

2.doReportStart()。如果Fragment上一次在销毁并重做,而且数据有效的话会在这里主动上报数据,最终走到callback的onLoadFinished中。
3.doStop()会停止mLoaders保存的所有Loader。最终是运行每一个Loader的onStopLoading()方法。
4.doDestroy()会清空所有有效和无效Loader,LoaderManager中不再存在任何Loader。
5.doRetain()会将LoaderManager的mRetaining状态置位true,并且保存retain时LoaderInfo的mStarted状态
6.finishRetain()如果之前所保存的mStarted与现在的不一样而且新的状态是停止的话,就停止掉这个Loader。否则若有数据并且不是要下次再上报(没有call doReportNextStart)的话就上报给callback的onLoadFinished。
7.doReportNextStart(),根据第6条,已经能够理解了。当Fragment执行到onDestroyView生命周期时,对自己的LoaderManager发出请求:即使现在有数据也不要进行上报,等我重做再到onStart生命周期时再给我。

外部接口:restartLoader

在熟知了LoaderManager的梗概之后最后分析restartLoader就能够更好理解了:
1.public <D> Loader<D> restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback)

1.若此ID对应的Loader之前使用过,则去除这个Loader,如果这个Loader不在运行中,则销毁它然后重新创建一个Loader;如果在运行中,则创建一个Loader等待在这个Loader后边
2.若此ID的Loader是新的,之前并没有使用过,则创建这个Loader,同initLoader。。



Loaders,装载机,适用于Android3.0以及更高的版本,它提供了一套在UI的主线程中异步加载数据的框架。使用Loaders可以非常简单的在Activity或者Fragment中异步加载数据,一般适用于大量的数据查询,或者需要经常修改并及时展示的数据显示到UI上,这样可以避免查询数据的时候,造成UI主线程的卡顿。

  Loaders有以下特点:

  • 可以适用于Activity和Fragment。
  • 可以提供异步的方式加载数据。
  • 监听数据源,当数据改变的时候,将新的数据发布到UI上。
  • Loaders使用Cursor加载数据,在更改Cursor的时候,会自动重新连接到最后配置的Cursor中读取数据,因此不需要重新查询数据。

0 0