Android应用程序的主线程就是咱们理解的界面线程,主要负责界面响应事件,因此须要避免其余不相干的事情在里面操做。若是主线程不能快速响应界面事件,将会获得一个不好的体验效果和ANR,那将是不能忍的一件事。若是有一个耗时操做或者其余和界面不相干的操做,建议是放在异步线程里面去作,对于一次性的操做,彷佛能够写个线程,若是有不按期的后台事件须要处理,每次都去开启线程,销毁线程,将会是很大浪费资源。若是有一个消息循环的话,每当你有任务须要处理,你能够把这个任务丢给队列,发送一个消息给消息循环,就能够了,执行操做的线程根据消息去执行队列里面的任务,这样只须要一个线程的开销,当你最后再也不使用的时候,销毁就能够了。java
在Android中主要有三种消息循环模型:一、应用程序主线程消息循环模型,主要是ActivityThread,二、与界面无关的应用程序子线程消息循环模型,主要是HandlerThread,三、是和界面相关的应用程序子线程消息循环模型,主要是AsyncTask。
android
ActivityThread:
app
Activity管理服务ActivityManagerService在启动一个应用程序组件,若是发现这个应用程序须要在新的应用程序中运行,就会调用Process类的静态成员函数start来启动一个新的应用程序,在start成员函数中会执行int pid = Process.start("android.app.ActivityThread",mSimpleProcessManagement?app.processName:null,uid,uid,gids,debugFlags,null);
异步
就会执行ActivityThread的静态成员函数Main的实现ide
//Android源码代码函数
public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
Looper.prepareMainLooper()的执行会在当前应用程序主线程中建立一个消息循环Looper对象,接着在Looper对象中建立一个MessageQueue对象,来描述一个应用程序主线程的消息队列。oop
Looper.loop()的执行使得当前应用程序主线程进入到当前所建立的一个消息循环中。post
Looper类的静态成员函数preparemainLooper只能在应用程序的主线程中调用,而且只能被调用一次,因为Looper类的静态成员函数prepareMainLooper在应用程序主线程启动的时候调用了一次,所以,不管在主线程仍是在子线程中,咱们都不会在调用他,不然就会收到一个运行时异常,ui
如何解决子线程不能操做应用程序界面的问题呢? 这个也是Looper存在的一个理由,Looper对象除了会保存一个线程局部变量中以外,还会单独保存在Looper类的静态成员变量mMainLooper中,这样咱们就能够在应用程序子线程中调用Looper的静态成员函数getMainLooper来得到主线程中的Looper对象,而且经过这个Looper对象像应用程序主线程的消息队列发送与界面操做相关的消息。这样就解决了 这个问题。this
HandlerThread:
在Java程序中咱们能够经过实现抽线类Thread或者继承Runnable接口,实现里面的run方法,来建立一个线程,可是这个线程是没有消息循环的一个做用,也就作不到操控界面的效果。若是须要有消息循环的线程能够使用HandlerThread类实现。
使用方法:
//HadnlerThread Android源码 这部分是粘贴Android源码
public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; //这是消息循环的Looper public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } /** * Constructs a HandlerThread. * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly over ridden if needed to execute some * setup before Looper loops. */ protected void onLooperPrepared() { } public void run() { mTid = Process.myTid(); Looper.prepare();//在执行strat以后,就会执行run,也就会执行这行代码,这里会建立一个MessageQueue对象,用来描述一个应用程序主线程的消息队列 synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop();//进入线程建立的一个消息循环中 mTid = -1; } /** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @return The looper. */ public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } /** * Ask the currently running looper to quit. If the thread has not * been started or has finished (that is if {@link #getLooper} returns * null), then false is returned. Otherwise the looper is asked to * quit and true is returned. */ public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; }
//使用方式 HandlerThread ht = new HandlerThread("a"); ht.start(); public class ThreadTask implements Runnable{ public void run(){ } } Handler handler = new Handler(ht.getLooper()); handler.post(new ThreadTask()); ht.quit();//退出前面建立的子线程
AsyncTask:
这个是Android提供的一个一部任务类,用来将一个涉及界面操做的任务放在一个子线程中执行,虽然异步任务子线程本身没有消息循环,可是它能够利用主线程的消息循环来执行界面相关的操做。
AsyncTask<Integer, Integer, Integer> task = new AsyncTask<Integer, Integer, Integer>(){ boolean stop; @Override protected Integer doInBackground(Integer... arg0) { // TODO Auto-generated method stub Integer initcounter = arg0[0]; stop = false; while(!stop){ publishProgress(initcounter); try{ Thread.sleep(1000); }catch(Exception e){ e.printStackTrace(); } initcounter++; } return initcounter; } @Override protected void onPostExecute(Integer result) { // TODO Auto-generated method stub super.onPostExecute(result); callback.count(val);//回调 } @Override protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); int val = values[0]; callback.count(val);//回调 } }; task.execute(1);
这是一个简单的计数器逻辑,callback是回调接口,用于显示在界面上。异步任务task的执行是在doInbackground中执行的,而且是运行在一个子线程中,所以不会影响主线程处理界面事件。计数器+1以后调用成员函数publishProgress方法将这个计数值分发给onProgressUpdate来处理,后者就经过回调更新到界面上,那么就意味这个这个方法执行在主线程中,不然就不能更新到界面中,缘由后面会分析,doInBackground方法返回以后,会将返回值分发给成员方法onPostExecute来处理,这个返回值就是异步任务task所描述的一个计数器的终止值,在这个方法里面也是经过回调更新到界面上,那么这个方法也是在主线程中执行的。接下来就接下为何一个方法执行的异步线程中,另外两个方法执行在主线程中,AsyncTask是如何作到的。首先让咱们看下Android源码:(因为字数限制,会单独开个文档copy源码)