您的位置:首页 > 移动开发 > Android开发

Android Loader机制 源码笔记(2)

2015-06-17 14:54 288 查看
Loader:

1. 本身是一个base类, 其注释里谈到了一些注意事项Loader的使用者应该遵循在任何时候对Loader的操作都在主线程(Activity的callback(onStart/XXX)发生的线程)进行, 而Loader的具体实现类,其耗时的操作可以也应该放在独立线程,传达结果这类操作应该在主线程完成

Loader的构造函数传入一个context,但是其内部使用的mContext实际是从该context获取的ApplicationContext(这样做的原因是Loader经常被跨Activity使用,如果和某个Activity绑定是不稳定也危险的).

register/unRegisterListener/OnLoadCanceledListener: 之前说过了, loadComplete和cancelLoade的callback.

Abandon状态: 这个状态下,loader有任何new的data都不应该再报告,而是要保留着最新的data知道其被reset.

Reset: 如果loader从没有被start过或者reset()函数被调用都会进入这个状态.

startLoading(): final 函数, 子类的定制主要在onStartLoading这个函数中, 其操作很简单: mStarted = true, mReset = false, mAbandoned = false. 然后调用onStartLoading, 只能在主线程调用,.

Loader作为一个base类,很多函数都是和上面的一样,一个基础函数只是改变一下状态,而子类的具体实现则放在另一个函数内,会被基础函数调用.

deliverResult(D data), 取到新data以后将其deliver出去,只能在主线程调用, 在base类只是简单的调用了Listener的onLoadComplete.

deliverCancellation(), 告知Listener loader已经被cancel了,只能在主线程调用,.

cancelLoad(): cancel loader,只能从主线程调用, 注意cancel并不是一个及时生效的操作,因为load操作是在另外一个线程运行的, 如果现在load正在进行中,那么cancel的作用是在load完成以后才会将loader 清除,而这时候如果有了其他的load请求过来,那么这个请求会一直pendig知道这个要被取消的loader真正被取消 , 在这种情况下, onLoadCancelListener会在load完成以后被调用

forceLoad(): 必须在主进程调用, 强行发起一次异步的load, 会直接忽略之前被load的data然后直接load新的, 这个函数会调用onFocceLoad(), 子类的实现一般都应该放在这里,而不是直接覆盖forceLoad这个函数

stopLoading(): 在loadManager所关联的Activity/Fragment stop时,会被自动调用, 会导致停止传递数据的更新, 直到startLoading被调用, 但是在具体实现时,不能在这一步就将上次的data无效化,使用者应该可以继续使用最近一次的data. 对于data变化还会继续监视,只不过不会再向调用者汇报.

abandon(): 在restart一个loader时会对该loader自动调用, 不要自己调用

takeContentChanged(): 用来获取在stop的这段时间里,data是否确实发生了变化,返回mContentChanged的值,同时将其设为false

onContentChanged(): 在ForceLoadContentObserver检测到data变化时会被调用,如果发现已经start了, 那么就会调用forceLoad,否则说明loader现在是停止的,不应该load新的data,但是需要有一个flag标识data已经变化,这样在后面start的时候会进行刷新,mContentChanged = true.

abstract class AsyncTaskLoader extends Loader: 一个实现了将load操作放入AyncTask的抽象base loader类:

定义了一个LoadTask extends AsyncTask Void, Void, D implements Runnable 类:

之所以即extends AsyncTask**又 implements Runnable**的原因是为了能在handler中进行延迟post(有时候有延迟执行的需求mUpdateThrottle就是反映这个的,注意这个延迟虽然是在主hanler上延迟的,但是延迟时间到了以后真正的执行还是在独立线程上执行的).

为了在Load完成时进行相应操作以及同步问题,这个类里使用了CountDownLatch, count设置为1,这意味这只要有一次countDown,await的线程就可以继续运行,而count的操作则是在两个函数内: onPostExecute(D data)和onCancelled(D data).

LoadTask有一个函数waitForLoader()调用了CountDownLatch的await函数,这个函数实现了调用者可以等待异步load完成的目的

在doInBackgroud函数中(独立线程),会调用外部AsyncTaskLoader对象的onLoadInBackground()来获取load的 data. 并且return.

而onPostExecute(D data)和onCancelled(D data)(都是在主线程)则会调用外部AsyncTaskLoader对象的dispatchOnLoadComplete(this, data)/dispatchOnCancelled(this, data)并countdown CountDownLatch来表示load已经完成.

AsyncTaskLoader维护了一个LoadTask对象 mTask, 在onForceLoad时会new一个LoadTask并赋给mTask.

dispatchOnCancelled(LoadTask task, D data), 先直接调用了onCancel, 然后如果发现当前保存的mCancellingTask就是传入的task, 那么会进行rollbackContentChanged(), 这个函数的作用是告知你已经abandon了由于takeContentChanged因此的content change, 因此会回滚到之前有pending content change的那个状态, 这个函数的应用场景是那些在一次load完成deliver data前,这次load被取消的场景.

然后将mCancellingTask设为null表示当前已经没有正在canceling的task了.

然后调用deliverCancellation()来进行对mOnLoadCanceledListener的回调, 一次成功的cancel.

最后一步executePendingTask开始将pending的loadtask进行执行新的Task需要等待旧的Task结束以后才能运行.

executePendingTask(): 只有在已经没有canceling的Task并且要执行的mTask不是null的情况下才会有实际操作, 这就是上面说的必须保证当前正在cancel的Task才能启动新的Task,, 如果发现mTask正在waiting(Loadtask的Waitting,的含义是LoaderTask被延迟post到了一个handler,还在等待被执行), 这时候会将LoaderTask的waiting设为false,并且将之前post的LoaderTask从mHandler中remove(因为要重新post一个), mHandle是在setUpdateThrottle(long delayMS)中初始化的,直接调用了默认的new handler()(那么这个handler应该和这个函数的调用线程是绑定的),如果在这一步指定了一个有效的mUpdateThrottle(比较当前时间以后发现当前还是需要等待的), 那么说明这次要run的loadTask也是一个需要延迟的,会将Task的waitting设置为true,然后mHanlder.postAtTime(…)进行延迟执行,如果发现可以立即执行这个task,那么会直接调用mTask的executeOnExecutor(mExecutor, (Void[]) null)来将mTask进行立刻执行, 这也是mTash还实现了Runnable接口的目的,为了实现延迟执行的效果.

dispatchOnLoadComplete(LoadTask task, D data): 如果发现传入的task不是当前维护的mTask,那么说明这个Task是一个被取消的old task(反正不是当前我们需要知道结果的LoadTask), 应该是被cancel掉的, ,现在终于等到了它运行结束,可以直接调用dispatchOnCancelled(task, data)来传的这次被cancel完成了, 否则,再检测是否已经abandon了,如果是,那么会执行onCanceled(D data), 这个回调的作用是提供给子类释放和清理已经用不上的这批data, 否则就是一次有效的,也是调用者希望得到的应该commit的 content change, 会调用commitContentChanged()标志着确实data发生了变化, 然后将mTask设为null标志着当前没有有效的LoaderTask(因为loader任务已经完成了), 最后执行deliverResult(data)将新的data传递出去. commitContentChanged()之前已经说过其作用,是为了标识当前确实有content change了. 而deliverResult()则是通过listener将得到的data传递出去(Listener的onLoadComplete(this, data) ->LoaderManager的onLoadComplete(this, data)->callOnLoadFinished(…)->mCallbacks.onLoadFinished).

waitForLoader()方法在之前说过,会调用mTask的waitForLoader阻塞等待Task的执行完成或者被取消.

isLoadInBackgroundCanceled()返回mCancellingTask != null来表明当前有没有正在被cancel的task.

cancelLoadInBackground()是一个空函数,由子类来具体实现, 应该在主线程调用来中止一次正在进行的load, 规定了如果task还没有开始或者已经结束,那么这个函数应该啥都不干.

abstract D loadInBackground()在protected D onLoadInBackground()中调用那个,建议实现类不要改变onLoadInBackground()而应该实现loadInBackground(), 而对loadInBackground()的具体实现,也有一些要求: 首先这个函数应该是在独立thread上运行的(废话), 具体实现不应该直接在这里将data投递出去,而应该将data返回,这个data最后会在主线程被投递出去, 如果你想定制化data投递的过程,那么应该去修改deliverResult函数而不是在这里, 而为了支持取消load, 实现的时候应该能够周期性的检测isLoadInBackgroundCanceled()这个函数(主线程调用用来终止task的load)并根据此来决定是否应该终止load, 当然了,子类也可以是直接override cancelLoadInBackground这个函数来直接的将load打断而不是轮询isLoadInBackgroundCanceled(), 当load被取消以后,这个方法既可以正常返回,也可以throw一个OperationCanceledException, 只要被取消,loader都会调用onCancel来进行取消后的clean-up并负责将data清理掉

onForceLoad(): 会先将当前的Load取消(cancelLoad), 然后new一个LoadTask并赋给mTask, 然后调用 executePendingTask()将新的mTask运行或者调度起来.

mTask和mCancellingTask都是volatile, 保证了赋值和调用的线程安全.

CursorLoader extends AsyncTaskLoader: 最常用的loader, 继承自AsyncTaskLoader: 因为父类已经实现了异步这个框架,CursorLoader要实现的只是load这个过程以及相关的清理.

CursorLoader既然和Cursor有光,那么在构造或是有相关的setter可以设置uri, projection, selection selectionArgs和sortOrder.

onCanceled(Cursor cursor)实现为如果cursor有效并且没有被close, 那么就会close.

onStopLoading()在主线程被调用,会调用cancelLoad().

Cursor loadInBackground(),具体实现为, 首先在开始前会检查一下isLoadInBackgroundCanceled()(注意需要同步),如果这时候就被cancel了,那么会抛出OperationCanceledException, 然后就开始利用之前得到的Uri/projection等信息来进行query(),会得到一个curosr, 如果得到的cursor不是null, 那么会运行Cursor.getCount来确保Cursor的window是被fill了,然后为Cursor注册一个内部的contentObserver(ForceLoadContentObserver mObserver), 中间有任何异常都会将cursor close并且继续throw. 注意这里在query的时候最后传入了一个mCancellationSignal参数以实现在load过程中的cancel

cancelLoadInBackground()就是利用了传入的mCancellationSignal, 会同步调用mCancellationSignal的cancel以实现对正在进行的load的cancel.

deliverResult的实现: 如果发现loader已经被reset了,那么会直接将返回的cursor close. 否则会将当前维护的mCursor替换为传入的curosr, 并且在super.deliverResult以后会将oldCursor close(这样就是之前注释说的在onLoadFinished被调用时, 旧的data并不会失效).

onStartLoading(): 在开始/重新开始load时,如果当前的mCursor不是null, 那么会将这个pending的mCurosr投递出去, 然后如果通过takeContentChanged()检测到sleep的时间内data发生了变化,那么就会调用forceLoad来提取最新的数据.

Loader中定义的ForceLoadContentObserver extends ContentObserver, 其构造时会传入一个new handler()作为onchange调用时所在的handler, ForceLoadContentObserver的onChange调用的是Loader的onContentChange().

ForceLoadContentObserver的deliverSelfNotifications返回是true,表明其愿意接受自己对content做修改而引起的notification.

CursorLoader是在自己的构造函数中new了ForceLoadContentObserver, 因此onChange()-> onContentChanged()调用发生的handler就是CursorLoader构造时所在的handler(一般都是主线程). onContentChanged()的逻辑在Loader类中,如果已经Loader是start的,那么会forceLoad(), 否则会将mContentChanged标记为true留待start时处理.

简单汇总: AsyncTask内部其实可以理解为是以LoadTask为单位来管理和控制进度的,一次Load行为就是发出去一个LoadTask对象, 同时在内部保留一个mTask来指向当前有效的loadTask,在之前old的loadTask返回时和会和mTask进行比对,如果发现不是当前有效的loadTask,那么就可以认为其是被cancel的task, 其返回的data也可以视为是无效的(因为在正常Task结束以后,mTask会设置为null)

forceLoad(其实实现是在onForceLoad中)的本质其实就是cancel当前正在进行的loadTask(),(这里的取消更像是一个标记而不是一种动作,取消标记是在LoadTask结束或者中止load返回时的回调中才会生效,表示这个LoadTask已经被cancel了),新构造一个LoaderTask并让mTask指向它表示当前有效的LoaderTask应该是这个新构造的Task,然后将新构造的LoadTask(一次新的Load)执行(如果当前没有正在cancle的load)或者调度起来(如果当前有正在cancel的load,那么会在这个load的cancel结束以后将这个新的Task run 起来).

cancelLoad()正如注释所说不是一个立刻生效的操作(在java中应该也不可能), 其构造和forceLoad比较相似,都是调用了一个protected的空函数onXX,然后由子类来具体实现,这种函数设计手法还是比较常见的, 对外的函数常常只是一个简单包装,里面调用的内部函数才是真正的实现主体并且一般由子类来进行实现, onCancelLoad在AsyncTaskLoader中的实现也很清晰,因为引入了延迟执行load的功能setUpdateThrottle(long delayMS), 因此在cancel当前的task时,可能被schedule的Task现在还没有开始(LoaderTask的waitting标识),那么直接把Task从handler中remove就达到了cancel的效果,mTask也会重置为null代表当前没有有效的Load任务, 否则如果LoaderTask已经run起来了,那么就不可能进行同步的取消了, 只能尝试AsyncTask本身的cancel方法(cancel(false)), 如果cancel()返回了true代表着AsyncTask**正在cancel(不是立即),可以将mCancellingTask设置为当前的mTask代表着当前正在cancel的Task, 并且调用cancelLoadInBackground()来将load in background这个过程cancel. 还有一种case是,在mCancellingTask还没有被cancel完毕,当前的mTask就又被cancel了, 这种情况下,mTask应该还在等待cancelingTask的结束,如果mTask被schedule了,那么就从handler 中 remove, 然后重置mTask即可, 这个task的onCancel不会被调用.**

AsyncTaskLoader中的LoaderTask继承自AsyncTask, 其执行(execute)所使用的是executeOnExecutor(…),和execute()的区别在于execute()使用的是AsynTask内部的SerialExecutor, 而前者则是可以自己指定一个Executor,AsyncTaskLoader默认使用的是AsynTask的THREAD_POOL_EXECUTOR
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: