2019-06-18 15:37:41 登录注册 RSS

当前位置: 公理网 >> 显明公道 >> AsyncTaskLoader设计原理大揭秘

AsyncTaskLoader设计原理大揭秘
发布时间:2018-08-23| 来源:公理网 | 点击发表评论
设计原理
在讲设计原理之前,先简单了解一下AsyncTaskLoader的父类Loader:

Aclassthatperformsasynchronousloadingofdata.WhileLoadersareactivetheyshouldmonitorthesourceoftheirdataanddelivernewresultswhenthecontentschange.SeeLoaderManagerformoredetail.
简单理解一下Loader就是用来异步加载数据的,当Loader处于活动状态的时候需要监视数据并且在数据发生改变时加载和分发新的数据。在上述描述中我们还发现了LoaderManager这个对象,正是因为有了它,Loader才具有生命力。

下面看一下LoaderManager的简单介绍:

InterfaceassociatedwithanActivityorFragmentformanagingoneormoreLoaderinstancesassociatedwithit.Thishelpsanapplicationmanagelonger-runningoperationsinconjunctionwiththeActivityorFragmentlifecycle;themostcommonuseofthisiswithaCursorLoader,howeverapplicationsarefreetowritetheirownloadersforloadingothertypesofdata.WhiletheLoaderManagerAPIwasintroducedinHONEYCOMB,aversionoftheAPIatisalsoavailableforuseonolderplatformsthroughFragmentActivity.SeetheblogpostFragmentsForAllformoredetails.
简单理解一下就是说LoaderManager是配合着Activity,Fragment的生命周期来管理Loader

接下来用一张类图来简单展示一下Loader,AsyncTaskLoader,AsyncTask,LoaderManager,Activity之间的关系

图-1相关类之间的关系?
20150830145200652"/>
接口

1.OnLoadCompleteListener


被声明在Loader中,用于Loader加载完数据后回调,从上图可以看出LoaderInfo实现了这个接口,说明当Loader完成数据加载后会回调LoaderInfo的onLoadComplete()方法。


2.LoaderCallbacks


被声明在LoaderManager中,从上图的LoaderInfo中可以看到mCallbacks这个变量,它便是LoaderCallbacks的引用,用于当Loader加载完数据后回调上面提及的onLoadComplete(),最终回调onLoadFinished()方法将最新加载的数据传递给客户端。



1.Loader


抽象类负责定义相关接口和约束。其变量mListener就是加载完数据的回调。那具体是如何回调的呢?答案就在deliverResult()方法中



Loader.java
--------------------------
publicvoiddeliverResult(Ddata){
if(mListener!=null){
mListener.onLoadComplete(this,data);
}

再看registerListener()方法:



Loader.java
--------------------------
publicvoidregisterListener(intid,OnLoadCompleteListenerDlistener){
if(mListener!=null){
thrownewIllegalStateException("Thereisalreadyalistenerregistered");
mListener=listener;
mId=id;
}

外部就是通过调用Loader的registerListener()方法将OnLoadCompleteListener接口注册进来的。


2.AsyncTaskLoader


继承自Loader,其中变量mTask正是AsyncTask类型,这里也论证了48092355"rel="nofollow">Android异步处理之AsyncTaskLoader简单使用中的说法,将AsyncTaskLoader比作面包师的话AsyncTask就是烤面包机的说法。AsyncTaskLoader中就是通过AsyncTask来完成异步加载数据这个操作的。


3.LoaderInfo


LoaderInfo其实是对Loader的一个封装,它掌握了Loader一系列的工作状态如:



LoaderInfo.java
-----------------------------
booleanmHaveData;
booleanmDeliveredData;
ObjectmData;
booleanmStarted;
booleanmRetaining;
booleanmRetainingStarted;
booleanmReportNextStart;
booleanmDestroyed;
booleanmListenerRegistered;

还有一系列的动作指令:



LoaderInfo.java
-----------------------------
voidstart(){...}
voidretain(){...}
voidreportStart(){...}
voidstop(){...}
voidcancel(){...}
voiddestroy(){...}

4.LoaderManager和LoaderManagerImpl


LoaderManager定义了作为Loader的管理者应该有哪些操作,而LoaderManagerImpl则具体实现这些操作。如果说把Loader比作面包师的话,那LoaderManager就算是面包店的老板吧,厨师什么时候该上班,什么时候该下班都由他管。?

其中mLoaders变量为一个数组,用于保存多个Loader这也说明了一个面包店可以有多个面包师负责制作不同类型的面包如:?
20150830153339817"/>?

这么多种类的面包如果让一个面包师来做我看他也会累的够呛。

运行流程梳理

在接下来的几步中有任何的疑惑都可以回过头看看【图1】。


那么了解上述这些类是干嘛的以后我们就来看看当这些个类运行起来是一个怎样的流程吧。?

我们还是接着48092355"rel="nofollow">Android异步处理之AsyncTaskLoader简单使用中的例子来讲。一切起源起于onCreate()(至少对于APP开发来说是这样),那就从MainActivity的onCreate()来看起吧。



@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里假设面包房刚开门的时候已经有9个人在排队了。
mNeededBreads=9;
mBaker=newBaker(this,mBreadCallback);
mBakery=newBakery(mBaker);
//1.实现`LoaderCallbacks`接口。
mCallbacks=newLoaderCallbacksListBread(){
@Override
publicLoaderListBreadonCreateLoader(intid,Bundleargs){
if(mBaker==null){
mBaker=newBaker(MainActivity.this,mBreadCallback);
returnmBaker;
@Override
publicvoidonLoadFinished(LoaderListBreadloader,ListBreaddata){
mNeededBreads=0;
Log.d("scott","sell"+data.size()+"breads");
@Override
publicvoidonLoaderReset(LoaderListBreadloader){
//2.在`LoaderManager`中注册这个接口。
getLoaderManager().restartLoader(mLoaderId,null,mCallbacks);
//3.模拟源源不断的顾客
mockCustomer();
}

这一步主要做了三件事情:?

1.实现LoaderCallbacks接口。?

2.在LoaderManager中注册这个接口。?

3.模拟源源不断的顾客?

那么这里的mCallbacks充当了什么角色呢?其实它应该相当于一个面包师Loader和面包房店长LoaderManager的中间桥梁。当店长需要面包师的时候就会调用onCreateLoader()来获得一个面包师。同样当面包师完成面包的烤制工作后就会调用onLoadFinished()来告诉店长面包做好了。但实际情况应该不会如此,面包做好了服务员应该会直接将面包传递给顾客。


接下来我们看一下restartLoader()这个方法:



LoaderManager.java
--------------------------------------------------------------
publicDLoaderDrestartLoader(intid,Bundleargs,LoaderManager.LoaderCallbacksDcallback){
LoaderInfoinfo=mLoaders.get(id);
//...省略部分代码
info=createAndInstallLoader(id,args,(LoaderManager.LoaderCallbacksObject)callback);
return(LoaderD)info.mLoader;
}

这里直接调用了createAndInstallLoader()方法来生成一个LoaderInfo对象。接着看createAndInstallLoader()方法:



LoaderManager.java
--------------------------------------------------------------
privateLoaderInfocreateAndInstallLoader(intid,Bundleargs,
LoaderManager.LoaderCallbacksObjectcallback){
try{
mCreatingLoader=true;
//1.创建LoaderInfo对象
LoaderInfoinfo=createLoader(id,args,callback);
//2.安装LoaderInfo对象
installLoader(info);
returninfo;
}finally{
mCreatingLoader=false;
}

这里分两步来看:?

1.创建LoaderInfo对象



LoaderInfo.java
------------------------------------------------------------
privateLoaderInfocreateLoader(intid,Bundleargs,
LoaderManager.LoaderCallbacksObjectcallback){
//实例化LoaderInfo,并将id,args,callback赋值给mId,mArgs,mCallbacks
LoaderInfoinfo=newLoaderInfo(id,args,(LoaderManager.LoaderCallbacksObject)callback);
//这里的callback就是上面onCreate中的mCallbacks
//获得Loader实例Baker
LoaderObjectloader=callback.onCreateLoader(id,args);
//将Baker赋值给info中的mLoader字段
info.mLoader=(LoaderObject)loader;
returninfo;
}

2.安装LoaderInfo对象



LoaderInfo.java
------------------------------------------------------------
voidinstallLoader(LoaderInfoinfo){
//将info放入mLoaders数组
mLoaders.put(info.mId,info);
//这一步mStarted=false,不会走下面的if条件语句,那么到这里一切都结束了?
if(mStarted){
//Theactivitywillstartallexistingloadersinit'sonStart(),
//soonlystartthemhereifwe'repastthatpointoftheactivitiy's
//lifecycle
info.start();
}

到这里其实我们已经不能在往下跟代码了,因为此时的mStarted=false,也就是说不会走info.start()这个方法。那么数据是在什么时候被加载的呢?冷静看上面的这段英文注释,Activity会在它的onStart()方法中启动所有已经存在的Loader,真是山穷水尽疑无路,柳暗花明又一村。我们就去onStart()中看个究竟。



Activity.java
------------------------------------------------------
protectedvoidonStart(){
if(DEBUG_LIFECYCLE)Slog.v(TAG,"onStart"+this);
mCalled=true;
if(!mLoadersStarted){
mLoadersStarted=true;
if(mLoaderManager!=null){
//看这里o(^▽^)o
mLoaderManager.doStart();
}elseif(!mCheckedForLoaderManager){
mLoaderManager=getLoaderManager("(root)",mLoadersStarted,false);
mCheckedForLoaderManager=true;
getApplication().dispatchActivityStarted(this);
}

继续LoaderManager的doStart()方法:



LoaderManager.java
--------------------------------------------------------------
voiddoStart(){
if(DEBUG)Log.v(TAG,"Startingin"+this);
if(mStarted){
RuntimeExceptione=newRuntimeException("here");
e.fillInStackTrace();
Log.w(TAG,"CalleddoStartwhenalreadystarted:"+this,e);
return;
mStarted=true;
//Callouttosubclassessotheycanstarttheirloaders
//Lettheexistingloadersknowthatwewanttobenotifiedwhenaloadiscomplete
//看,在这里LoaderInfo被启动了
for(inti=mLoaders.size()-1;ii--){
mLoaders.valueAt(i).start();
}

下面转移战场进入LoaderInfo看看



LoaderInfo.java
--------------------------------------------
voidstart(){
//...
mStarted=true;
if(mLoader==nullmCallbacks!=null){
mLoader=mCallbacks.onCreateLoader(mId,mArgs);
if(mLoader!=null){
//...
if(!mListenerRegistered){
//将OnLoadCompleteListener接口注册给Loader
mLoader.registerListener(mId,this);
//将OnLoadCanceledListener接口注册给Loader
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered=true;
//开始加载,实质性的一步。
mLoader.startLoading();
}

进入Loader的startLoading()方法看看:



Loader.java
--------------------------------------------
publicfinalvoidstartLoading(){
mStarted=true;
mReset=false;
mAbandoned=false;
onStartLoading();
}

接着看onStartLoading():



Loader.java
--------------------------------------------
*Subclassesmustimplementthistotakecareofloadingtheirdata,
*asper{@link#startLoading()}.Thisisnotcalledbyclientsdirectly,
*butasaresultofacallto{@link#startLoading()}.
protectedvoidonStartLoading(){
}

注释写的很清楚,子类必须要覆盖这个方法,接着我们看看我们久违的Baker(比忘了Baker可是Loader的子类啊)吧:



Baker.java
--------------------------------------------
@Override
protectedvoidonStartLoading(){
//这个可以解释为强行加载,太暴力了。
forceLoad();
}

那么forceLoad()又是哪里的呢?



Loader.java
--------------------------------------------
*Forceanasynchronousload.Unlike{@link#startLoading()}thiswillignoreapreviously
*loadeddatasetandloadanewone.Thissimplycallsthroughtothe
*implementation's{@link#onForceLoad()}.Yougenerallyshouldonlycallthis
*whentheloaderisstarted--thatis,{@link#isStarted()}returnstrue.
*pMustbecalledfromtheprocess'smainthread.
publicvoidforceLoad(){
onForceLoad();
}

接着看onForceLoad():



Loader.java
--------------------------------------------
*Subclassesmustimplementthistotakecareofrequeststo{@link#forceLoad()}.
*Thiswillalwaysbecalledfromtheprocess'smainthread.
protectedvoidonForceLoad(){
}

又来这套。。。服了Google的工程师了。接着在AsyncTaskLoader中找到了onForceLoad():



AsyncTaskLoader.java
--------------------------------------------
@Override
protectedvoidonForceLoad(){
super.onForceLoad();
cancelLoad();
//这里的LoadTask继承自AsyncTask
mTask=newLoadTask();
if(DEBUG)Log.v(TAG,"Preparingload:mTask="+mTask);
//执行准备就绪的mTask
executePendingTask();
}

接着看executePendingTask():



AsyncTaskLoader.java
--------------------------------------------
voidexecutePendingTask(){
if(mCancellingTask==nullmTask!=null){
//...
//...
//到这里mTask就真正被执行了,即烤面包机考试工作了。
mTask.executeOnExecutor(mExecutor,(Void[])null);
}

接下来我们来看一下mTask对应的类LoadTask的定义吧。



finalclassLoadTaskextendsAsyncTaskVoid,Void,DimplementsRunnable{
privatefinalCountDownLatchmDone=newCountDownLatch(1);
//Settotruetoindicatethatthetaskhasbeenpostedtoahandlerfor
//executionatalatertime.Usedtothrottleupdates.
booleanwaiting;
/*Runsonaworkerthread*/
@Override
protectedDdoInBackground(Void...params){
if(DEBUG)Log.v(TAG,this+"doInBackground");
try{
Ddata=AsyncTaskLoader.this.onLoadInBackground();
if(DEBUG)Log.v(TAG,this+"doInBackground");
returndata;
}catch(OperationCanceledExceptionex){
//...
if(DEBUG)Log.v(TAG,this+"doInBackground(wascanceled)",ex);
returnnull;
/*RunsontheUIthread*/
@Override
protectedvoidonPostExecute(Ddata){
if(DEBUG)Log.v(TAG,this+"onPostExecute");
try{
AsyncTaskLoader.this.dispatchOnLoadComplete(this,data);
}finally{
mDone.countDown();
/*RunsontheUIthread*/
@Override
protectedvoidonCancelled(Ddata){
//...
/*RunsontheUIthread,whenthewaitingtaskispostedtoahandler.
*Thismethodisonlyexecutedwhentaskexecutionwasdeferred(waitingwastrue).*/
@Override
publicvoidrun(){
//...
/*Usedfortestingpurposestowaitforthetasktocomplete.*/
publicvoidwaitForLoader(){
//...
}

这里有两个方法需要关注:?

1.doInBackground()方法?

用过AsyncTask的应该都了解,异步操作都是放在这里执行的,我们看一下都做了什么操作?



Ddata=AsyncTaskLoader.this.onLoadInBackground();

接着看onLoadInBackground:



protectedDonLoadInBackground(){
returnloadInBackground();
}

这个loadInBackground()是不是有点熟悉了?没错这就是我们在Baker中重写的方法:



Baker.java
------------------------------------------------------
@Override
publicListBreadloadInBackground(){
ListBreadbreads=newArrayListBread
intneeds=mCallback.getNeededBreads();
for(inti=0;ineeds;i++){
breads.add(newBread());
returnbreads;
}

OK,到这里面包已经烤完(耗时操作),接着就看这些香喷喷的面包怎么到顾客的手里的吧?


2.onPostExecute()方法



LoadTask.java
-------------------------------------------------
@Override
protectedvoidonPostExecute(Ddata){
if(DEBUG)Log.v(TAG,this+"onPostExecute");
try{
AsyncTaskLoader.this.dispatchOnLoadComplete(this,data);
}finally{
mDone.countDown();
}

走的是dispatchOnLoadComplete()方法:



AsyncTaskLoader.java
------------------------------------------------------
voiddispatchOnLoadComplete(LoadTasktask,Ddata){
if(mTask!=task){
if(DEBUG)Log.v(TAG,"Loadcompleteofoldtask,tryingtocancel");
//容错处理
dispatchOnCancelled(task,data);
}else{
if(isAbandoned()){
//Thiscursorhasbeenabandoned;justcancelthenewdata.
onCanceled(data);
}else{
commitContentChanged();
mLastLoadCompleteTime=SystemClock.uptimeMillis();
mTask=null;
if(DEBUG)Log.v(TAG,"Deliveringresult");
//重点在这里
deliverResult(data);
}

继续往下走deliverResult(data):



Loader.java
------------------------------------------------------
publicvoiddeliverResult(Ddata){
if(mListener!=null){
//这里的mListener就是之前在【5】中注册的OnLoadCompleteListener接口
mListener.onLoadComplete(this,data);
}

那么自然又要转移到LoaderInfo中的onLoadComplete()中去了:



LoaderInfo.java
------------------------------------------------------
@Override
publicvoidonLoadComplete(LoaderObjectloader,Objectdata){
//...
if(mLoaders.get(mId)!=this){
//Thisdataisnotcomingfromthecurrentactiveloader.
//Wedon'tcareaboutit.
if(DEBUG)Log.v(TAG,"Ignoringloadcomplete--notactive");
return;
LoaderInfopending=mPendingLoader;
if(pending!=null){
//Thereisanewrequestpendingandwewerejust
//waitingfortheoldonetocompletebeforestarting
//it.Sonowitistime,switchovertothenewloader.
//...
return;
//Notifyofthenewdatasotheappcanswitchouttheolddatabefore
//wetrytodestroyit.
if(mData!=data||!mHaveData){
mData=data;
mHaveData=true;
if(mStarted){
//重点看这里
callOnLoadFinished(loader,data);
//if(DEBUG)Log.v(TAG,"onLoadFinishedreturned:"+this);
//Wehavenowgiventheapplicationthenewloaderwithits
//loadeddata,soitshouldhavestoppedusingtheprevious
//loader.Ifthereisapreviousloaderontheinactivelist,
//cleanitup.
//...
}

继续看callOnLoadFinished():



LoaderInfo.java
------------------------------------------------------
voidcallOnLoadFinished(LoaderObjectloader,Objectdata){
if(mCallbacks!=null){
//...
try{
if(DEBUG)Log.v(TAG,"onLoadFinishedin"+loader+":"
+loader.dataToString(data));
//这里是重点了
mCallbacks.onLoadFinished(loader,data);
}finally{
//...
mDeliveredData=true;
}

mCallbacks又是什么呢?在第【3】步中的:



//实例化LoaderInfo,并将id,args,callback赋值给mId,mArgs,mCallbacks
LoaderInfoinfo=newLoaderInfo(id,args,(LoaderManager.LoaderCallbacksObject)callback);

而这里的callback就是我们在第【1】步中定义的mCallbacks对象。?

饶了这么大一圈,最后还是走到了第【1】步中的:



@Override
publicvoidonLoadFinished(LoaderListBreadloader,ListBreaddata){
mNeededBreads=0;
//此时面包以成功送至顾客手中(相当于将数据更新在UI上,这里是main线程大家大可放心使用这些数据)
Log.d("scott","sell"+data.size()+"breads");
}

那么到此为止这个流程就走完了。

总结

1.Loader可以配合中Activity或Fragment的生命周期来加载数据。?

2.读源码的时候画类关系图很重要!读源码的时候画类关系图很重要!读源码的时候画类关系图很重要!?

3.文章写的仓促,如果有有问题的地方欢迎指出。


设计原理与实现——虚拟机概述">JVM设计原理与实现——虚拟机概述
tr1912

10-151400

最近小编正在读《揭秘java虚拟机JVM设计原理与实现》,顺便总结一下成一个系列记录一下读书的历程吧(挺厚的一本书,怕读不完)!一、来源????其实这个问题应该从编程语言的始祖说...


AsyncTaskLoader简单使用">Android异步处理之AsyncTaskLoader简单使用
zqlite

08-293947

不管是在Android应用开发还是Android平台开发中,异步处理通常是最基本的coding要求。如果你还在主线程中写一些数据库,网络请求,读写本地文件等操作的话那说明你还不是一个合格的Androi...


揭秘Java虚拟机-JVM设计原理与实现pdf免费下载">揭秘Java虚拟机-JVM设计原理与实现pdf免费下载
987654321.jpg"alt="change987654321">change987654321

08-1628

免费下载地址:https://pan.baidu.com/s/1vbhmXimlfYSnoegs8ncamA


AsyncTaskLoader的使用">Android异步任务处理之AsyncTaskLoader的使用
happy_horse

05-276398

最近项目中涉及到加载本地的地名.db文件,数据量大,自然不能直接放在UI线程中操作,好在Google在Android3.0以后,提供了AsyncTaskLoader来做一些耗时的异步任务。一官方对A...

最新新闻

手机浏览

公理网 版权所有

公理网 Total 0.041308(s) query 6, 报料QQ:点击这里

给我发消息