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源碼)