Android应用程序的主线程就是我们理解的界面线程,主要负责界面响应事件,所以需要避免其他不相干的事情在里面操作。如果主线程不能快速响应界面事件,将会得到一个很差的体验效果和ANR,那将是不能忍的一件事。如果有一个耗时操作或者其他和界面不相干的操作,建议是放在异步线程里面去做,对于一次性的操作,似乎可以写个线程,如果有不定期的后台事件需要处理,每次都去开启线程,销毁线程,将会是很大浪费资源。如果有一个消息循环的话,每当你有任务需要处理,你可以把这个任务丢给队列,发送一个消息给消息循环,就可以了,执行操作的线程根据消息去执行队列里面的任务,这样只需要一个线程的开销,当你最后不再使用的时候,销毁就可以了。

在Android中主要有三种消息循环模型:1、应用程序主线程消息循环模型,主要是ActivityThread,2、与界面无关的应用程序子线程消息循环模型,主要是HandlerThread,3、是和界面相关的应用程序子线程消息循环模型,主要是AsyncTask。

ActivityThread:

Activity管理服务ActivityManagerService在启动一个应用程序组件,如果发现这个应用程序需要在新的应用程序中运行,就会调用Process类的静态成员函数start来启动一个新的应用程序,在start成员函数中会执行int pid = Process.start("android.app.ActivityThread",mSimpleProcessManagement?app.processName:null,uid,uid,gids,debugFlags,null);

就会执行ActivityThread的静态成员函数Main的实现

//Android源码代码

publicstaticvoidmain(String[]args){SamplingProfilerIntegration.start();//CloseGuarddefaultstotrueandcanbequitespammy.We//disableithere,butselectivelyenableitlater(via//StrictMode)ondebugbuilds,butusingDropBox,notlogs.CloseGuard.setEnabled(false);Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();if(sMainThreadHandler==null){sMainThreadHandler=newHandler();}ActivityThreadthread=newActivityThread();thread.attach(false);if(false){Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG,"ActivityThread"));}Looper.loop();thrownewRuntimeException("Mainthreadloopunexpectedlyexited");}

Looper.prepareMainLooper()的执行会在当前应用程序主线程中创建一个消息循环Looper对象,接着在Looper对象中创建一个MessageQueue对象,来描述一个应用程序主线程的消息队列。

Looper.loop()的执行使得当前应用程序主线程进入到当前所创建的一个消息循环中。

Looper类的静态成员函数preparemainLooper只能在应用程序的主线程中调用,并且只能被调用一次,由于Looper类的静态成员函数prepareMainLooper在应用程序主线程启动的时候调用了一次,因此,无论在主线程还是在子线程中,我们都不会在调用他,否则就会收到一个运行时异常,

如何解决子线程不能操作应用程序界面的问题呢? 这个也是Looper存在的一个理由,Looper对象除了会保存一个线程局部变量中之外,还会单独保存在Looper类的静态成员变量mMainLooper中,这样我们就可以在应用程序子线程中调用Looper的静态成员函数getMainLooper来获得主线程中的Looper对象,并且通过这个Looper对象像应用程序主线程的消息队列发送与界面操作相关的消息。这样就解决了 这个问题。


HandlerThread:

在Java程序中我们可以通过实现抽线类Thread或者继承Runnable接口,实现里面的run方法,来创建一个线程,但是这个线程是没有消息循环的一个作用,也就做不到操控界面的效果。如果需要有消息循环的线程可以使用HandlerThread类实现。

使用方法:

//HadnlerThread Android源码 这部分是粘贴Android源码

publicclassHandlerThreadextendsThread{intmPriority;intmTid=-1;LoopermLooper;//这是消息循环的LooperpublicHandlerThread(Stringname){super(name);mPriority=Process.THREAD_PRIORITY_DEFAULT;}/***ConstructsaHandlerThread.*@paramname*@parampriorityTheprioritytorunthethreadat.Thevaluesuppliedmustbefrom*{@linkandroid.os.Process}andnotfromjava.lang.Thread.*/publicHandlerThread(Stringname,intpriority){super(name);mPriority=priority;}/***Callbackmethodthatcanbeexplicitlyoverriddenifneededtoexecutesome*setupbeforeLooperloops.*/protectedvoidonLooperPrepared(){}publicvoidrun(){mTid=Process.myTid();Looper.prepare();//在执行strat之后,就会执行run,也就会执行这行代码,这里会创建一个MessageQueue对象,用来描述一个应用程序主线程的消息队列synchronized(this){mLooper=Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();//进入线程创建的一个消息循环中mTid=-1;}/***ThismethodreturnstheLooperassociatedwiththisthread.Ifthisthreadnotbeenstarted*orforanyreasonisisAlive()returnsfalse,thismethodwillreturnnull.Ifthisthread*hasbeenstarted,thismethodwillblockuntilthelooperhasbeeninitialized.*@returnThelooper.*/publicLoopergetLooper(){if(!isAlive()){returnnull;}//Ifthethreadhasbeenstarted,waituntilthelooperhasbeencreated.synchronized(this){while(isAlive()&&mLooper==null){try{wait();}catch(InterruptedExceptione){}}}returnmLooper;}/***Askthecurrentlyrunningloopertoquit.Ifthethreadhasnot*beenstartedorhasfinished(thatisif{@link#getLooper}returns*null),thenfalseisreturned.Otherwisethelooperisaskedto*quitandtrueisreturned.*/publicbooleanquit(){Looperlooper=getLooper();if(looper!=null){looper.quit();returntrue;}returnfalse;}/***Returnstheidentifierofthisthread.SeeProcess.myTid().*/publicintgetThreadId(){returnmTid;}
//使用方式HandlerThreadht=newHandlerThread("a");ht.start();publicclassThreadTaskimplementsRunnable{publicvoidrun(){}}Handlerhandler=newHandler(ht.getLooper());handler.post(newThreadTask());ht.quit();//退出前面创建的子线程


AsyncTask:

这个是Android提供的一个一部任务类,用来将一个涉及界面操作的任务放在一个子线程中执行,虽然异步任务子线程自己没有消息循环,但是它可以利用主线程的消息循环来执行界面相关的操作。

AsyncTask<Integer,Integer,Integer>task=newAsyncTask<Integer,Integer,Integer>(){booleanstop;@OverrideprotectedIntegerdoInBackground(Integer...arg0){//TODOAuto-generatedmethodstubIntegerinitcounter=arg0[0];stop=false;while(!stop){publishProgress(initcounter);try{Thread.sleep(1000);}catch(Exceptione){e.printStackTrace();}initcounter++;}returninitcounter;}@OverrideprotectedvoidonPostExecute(Integerresult){//TODOAuto-generatedmethodstubsuper.onPostExecute(result);callback.count(val);//回调}@OverrideprotectedvoidonProgressUpdate(Integer...values){//TODOAuto-generatedmethodstubsuper.onProgressUpdate(values);intval=values[0];callback.count(val);//回调}};task.execute(1);

这是一个简单的计数器逻辑,callback是回调接口,用于显示在界面上。异步任务task的执行是在doInbackground中执行的,并且是运行在一个子线程中,因此不会影响主线程处理界面事件。计数器+1之后调用成员函数publishProgress方法将这个计数值分发给onProgressUpdate来处理,后者就通过回调更新到界面上,那么就意味这个这个方法执行在主线程中,否则就不能更新到界面中,原因后面会分析,doInBackground方法返回之后,会将返回值分发给成员方法onPostExecute来处理,这个返回值就是异步任务task所描述的一个计数器的终止值,在这个方法里面也是通过回调更新到界面上,那么这个方法也是在主线程中执行的。接下来就接下为什么一个方法执行的异步线程中,另外两个方法执行在主线程中,AsyncTask是如何做到的。首先让我们看下Android源码:(由于字数限制,会单独开个文档copy源码




更多相关文章

  1. Android异步任务的处理方法
  2. Android消息队列(二)--异步消息处理
  3. 浅谈android的线程池
  4. Android资源管理框架(Asset Manager)简要介绍和学习计划
  5. Android进程与线程[转]
  6. android应用程序类型
  7. Android面试的一些总结
  8. Android中多线程下载列表实现
  9. Android——AsyncTask

随机推荐

  1. Github最火!程序员必须知道22大定律和法则
  2. python常用的图像处理工具有哪些?工具推
  3. Ryft Cloud迁移到AWS EC2 F1实例上来了!
  4. 频谱分析仪中的 Spartan-6 FPGA
  5. Xilinx FPGA在基因组测序中大显身手!
  6. 五巨头联合打造高可靠性IIOT方案
  7. 请注意写代码的习惯与态度(Java)
  8. CSS样式表优先级及模块化原理及实现
  9. 【案例】学习flex项目上的三个属性并尝试
  10. Prometheus监控系统 之 安装部署