• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            xiaoguozi's Blog
            Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習慣原本生活的人不容易改變,就算現狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預料,人們需要更細心的觀察別人,要隨時注意才能保護別人,因為他們未必知道自己要什么·····

            我們知道,Android應用程序是通過消息來驅動的,即在應用程序的主線程(UI線程)中有一個消息循環,負責處理消息隊列中的消息。我們也知 道,Android應用程序是支持多線程的,即可以創建子線程來執行一些計算型的任務,那么,這些子線程能不能像應用程序的主線程一樣具有消息循環呢?這 些子線程又能不能往應用程序的主線程中發送消息呢?本文將分析Android應用程序線程消息處理模型,為讀者解答這兩個問題

             

                    在開發Android應用程序中,有時候我們需要在應用程序中創建一些常駐的子線程來不定期地執行一些不需要與應用程序界面交互的計算型的任務。如果這些 子線程具有消息循環,那么它們就能夠常駐在應用程序中不定期的執行一些計算型任務了:當我們需要用這些子線程來執行任務時,就往這個子線程的消息隊列中發 送一個消息,然后就可以在子線程的消息循環中執行我們的計算型任務了。我們在前面一篇文章Android系統默認Home應用程序(Launcher)的 啟動過程源代碼分析中,介紹Launcher的啟動過程時,在Step 15(LauncherModel.startLoader)中,Launcher就是通過往一個子線程的消息隊列中發送一個消息 (sWorker.post(mLoaderTask)),然后子線程就會在它的消息循環中處理這個消息的時候執行從 PackageManagerService中獲取系統中已安裝應用程序的信息列表的任務,即調用Step 16中的LoaderTask.run函數。

             

                    在開發Android應用程序中,有時候我們又需要在應用程序中創建一些子線程來執行一些需要與應用程序界面進交互的計算型任務。典型的應用場景是當我們要從網上下載文 件時,為了不使主線程被阻塞,我們通常創建一個子線程來負責下載任務,同時,在下載的過程,將下載進度以百分比的形式在應用程序的界面上顯示出來,這樣就 既不會阻塞主線程的運行,又能獲得良好的用戶體驗。但是,我們知道,Android應用程序的子線程是不可以操作主線程的UI的,那么,這個負責下載任務 的子線程應該如何在應用程序界面上顯示下載的進度呢?如果我們能夠在子線程中往主線程的消息隊列中發送消息,那么問題就迎刃而解了,因為發往主線程消息隊 列的消息最終是由主線程來處理的,在處理這個消息的時候,我們就可以在應用程序界面上顯示下載進度了。

             

                    上面提到的這兩種情況,Android系統都為我們提供了完善的解決方案,前者可以通過使用HandlerThread類來實現,而后者可以使用 AsyncTask類來實現,本文就詳細這兩個類是如何實現的。不過,為了更好地理解HandlerThread類和AsyncTask類的實現,我們先 來看看應用程序的主線程的消息循環模型是如何實現的。

             

                    1. 應用程序主線程消息循環模型

             

                    在前面一篇文章Android應用程序進程啟動過程的源代碼分析一文中,我們已經分析應用程序進程(主線程)的啟動過程了,這里主要是針對它的消息循環模 型作一個總結。當運行在Android應用程序框架層中的ActivityManagerService決定要為當前啟動的應用程序創建一個主線程的時 候,它會在ActivityManagerService中的startProcessLocked成員函數調用Process類的靜態成員函數 start為當前應用程序創建一個主線程:

             

             

            view plaincopy to clipboardprint?public final class ActivityManagerService extends ActivityManagerNative     

                    implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {     

                 

                ......     

                 

                private final void startProcessLocked(ProcessRecord app,     

                            String hostingType, String hostingNameStr) {     

                 

                    ......     

                 

                    try {     

                        int uid = app.info.uid;     

                        int[] gids = null;     

                        try {     

                            gids = mContext.getPackageManager().getPackageGids(     

                                app.info.packageName);     

                        } catch (PackageManager.NameNotFoundException e) {     

                            ......     

                        }     

                             

                        ......     

                 

                        int debugFlags = 0;     

                             

                        ......     

                             

                        int pid = Process.start("android.app.ActivityThread",     

                            mSimpleProcessManagement ? app.processName : null, uid, uid,     

                            gids, debugFlags, null);     

                             

                        ......     

                 

                    } catch (RuntimeException e) {     

                             

                        ......     

                 

                    }     

                }     

                 

                ......     

                 

            }     

            public final class ActivityManagerService extends ActivityManagerNative   

                    implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {   

               

                ......    

               

                private final void startProcessLocked(ProcessRecord app,   

                            String hostingType, String hostingNameStr) {   

               

                    ......   

               

                    try {   

                        int uid = app.info.uid;   

                        int[] gids = null;   

                        try {   

                            gids = mContext.getPackageManager().getPackageGids(   

                                app.info.packageName);   

                        } catch (PackageManager.NameNotFoundException e) {   

                            ......   

                        }   

                           

                        ......   

               

                        int debugFlags = 0;   

                           

                        ......   

                           

                        int pid = Process.start("android.app.ActivityThread",   

                            mSimpleProcessManagement ? app.processName : null, uid, uid,   

                            gids, debugFlags, null);   

                           

                        ......   

               

                    } catch (RuntimeException e) {   

                           

                        ......   

               

                    }   

                }   

               

                ......   

               

            }            這里我們主要關注Process.start函數的第一個參數“android.app.ActivityThread”,它表示要在當前新建的線程中加 載android.app.ActivityThread類,并且調用這個類的靜態成員函數main作為應用程序的入口點。ActivityThread 類定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

             

             

            view plaincopy to clipboardprint?public final class ActivityThread {   

                ......   

               

                public static final void main(String[] args) {   

                    ...... 

               

                    Looper.prepareMainLooper();   

                      

                    ......   

               

                    ActivityThread thread = new ActivityThread();   

                    thread.attach(false);   

               

                    ......  

                    Looper.loop();   

               

                    ......  

               

                    thread.detach();   

                    ......   

                }   

               

                ......   

            }   

            public final class ActivityThread { 

                ...... 

             

                public static final void main(String[] args) { 

                    ......

             

                    Looper.prepareMainLooper(); 

                    

                    ...... 

             

                    ActivityThread thread = new ActivityThread(); 

                    thread.attach(false); 

             

                    ......

                    Looper.loop(); 

             

                    ......

             

                    thread.detach(); 

                    ...... 

                } 

             

                ...... 

            }          在這個main函數里面,除了創建一個ActivityThread實例外,就是在進行消息循環了。

             

                    在進行消息循環之前,首先會通過Looper類的靜態成員函數prepareMainLooper為當前線程準備一個消息循環對象。Looper類定義在 frameworks/base/core/java/android/os/Looper.java文件中:

             

             

            view plaincopy to clipboardprint?public class Looper { 

                ...... 

             

                // sThreadLocal.get() will return null unless you've called prepare().  

                private static final ThreadLocal sThreadLocal = new ThreadLocal(); 

             

                ...... 

             

                private static Looper mMainLooper = null; 

             

                ...... 

             

                public static final void prepare() { 

                    if (sThreadLocal.get() != null) { 

                        throw new RuntimeException("Only one Looper may be created per thread"); 

                    } 

                    sThreadLocal.set(new Looper()); 

                } 

             

                ...... 

             

                public static final void prepareMainLooper() { 

                    prepare(); 

                    setMainLooper(myLooper()); 

                    ...... 

                } 

             

                private synchronized static void setMainLooper(Looper looper) { 

                    mMainLooper = looper; 

                } 

             

                public synchronized static final Looper getMainLooper() { 

                    return mMainLooper; 

                } 

             

                ...... 

             

                public static final Looper myLooper() { 

                    return (Looper)sThreadLocal.get(); 

                } 

             

                ...... 

            public class Looper {

            ......

             

            // sThreadLocal.get() will return null unless you've called prepare().

            private static final ThreadLocal sThreadLocal = new ThreadLocal();

             

            ......

             

            private static Looper mMainLooper = null;

             

            ......

             

            public static final void prepare() {

            if (sThreadLocal.get() != null) {

            throw new RuntimeException("Only one Looper may be created per thread");

            }

            sThreadLocal.set(new Looper());

            }

             

            ......

             

            public static final void prepareMainLooper() {

            prepare();

            setMainLooper(myLooper());

            ......

            }

             

            private synchronized static void setMainLooper(Looper looper) {

            mMainLooper = looper;

            }

             

            public synchronized static final Looper getMainLooper() {

            return mMainLooper;

            }

             

            ......

             

            public static final Looper myLooper() {

            return (Looper)sThreadLocal.get();

            }

             

            ......

            }

             

                    Looper類的靜態成員函數prepareMainLooper是專門應用程序的主線程調用的,應用程序的其它子線程都不應該調用這個函數來在本線程中 創建消息循環對象,而應該調用prepare函數來在本線程中創建消息循環對象,下一節我們介紹一個線程類HandlerThread 時將會看到。

             

                    為什么要為應用程序的主線程專門準備一個創建消息循環對象的函數呢?這是為了讓其它地方能夠方便地通過Looper類的getMainLooper函數來 獲得應用程序主線程中的消息循環對象。獲得應用程序主線程中的消息循環對象又有什么用呢?一般就是為了能夠向應用程序主線程發送消息了。

             

                    在prepareMainLooper函數中,首先會調用prepare函數在本線程中創建一個消息循環對象,然后將這個消息循環對象放在線程局部變量sThreadLocal中:

             

             

            view plaincopy to clipboardprint?sThreadLocal.set(new Looper()); 

            sThreadLocal.set(new Looper());        接著再將這個消息循環對象通過調用setMainLooper函數來保存在Looper類的靜態成員變量mMainLooper中:

             

             

            view plaincopy to clipboardprint?mMainLooper = looper; 

            mMainLooper = looper;       這樣,其它地方才可以調用getMainLooper函數來獲得應用程序主線程中的消息循環對象。

             

                   消息循環對象創建好之后,回到ActivityThread類的main函數中,接下來,就是要進入消息循環了:

             

             

            view plaincopy to clipboardprint?Looper.loop();  

            Looper.loop();         Looper類具體是如何通過loop函數進入消息循環以及處理消息隊列中的消息,可以參考前面一篇文章Android應用程序消息處理機制 (Looper、Handler)分析,這里就不再分析了,我們只要知道ActivityThread類中的main函數執行了這一步之后,就為應用程序 的主線程準備好消息循環就可以了。

             

                    2. 應用程序子線程消息循環模型

             

                    在Java框架中,如果我們想在當前應用程序中創建一個子線程,一般就是通過自己實現一個類,這個類繼承于Thread類,然后重載Thread類的 run函數,把我們想要在這個子線程執行的任務都放在這個run函數里面實現。最后實例這個自定義的類,并且調用它的start函數,這樣一個子線程就創 建好了,并且會調用這個自定義類的run函數。但是當這個run函數執行完成后,子線程也就結束了,它沒有消息循環的概念。

             

                    前面說過,有時候我們需要在應用程序中創建一些常駐的子線程來不定期地執行一些計算型任務,這時候就可以考慮使用Android系統提供的HandlerThread類了,它具有創建具有消息循環功能的子線程的作用。

             

                    HandlerThread類實現在frameworks/base/core/java/android/os/HandlerThread.java文件中,這里我們通過使用情景來有重點的分析它的實現。

             

                    在前面一篇文章Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析中,我們分析了Launcher的啟動過程,其中在 Step 15(LauncherModel.startLoader)和Step 16(LoaderTask.run)中,Launcher會通過創建一個HandlerThread類來實現在一個子線程加載系統中已經安裝的應用程序 的任務:

             

             

            view plaincopy to clipboardprint?public class LauncherModel extends BroadcastReceiver { 

                ...... 

             

                private LoaderTask mLoaderTask; 

             

                private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader"); 

                static { 

                    sWorkerThread.start(); 

                } 

                private static final Handler sWorker = new Handler(sWorkerThread.getLooper()); 

             

                ...... 

             

                public void startLoader(Context context, boolean isLaunching) {   

                    ......   

             

                    synchronized (mLock) {   

                        ......   

             

                        // Don't bother to start the thread if we know it's not going to do anything    

                        if (mCallbacks != null && mCallbacks.get() != null) {   

                            ...... 

             

                            mLoaderTask = new LoaderTask(context, isLaunching);   

                            sWorker.post(mLoaderTask);   

                        }   

                    }   

                }   

             

                ...... 

             

                private class LoaderTask implements Runnable {   

                    ......   

             

                    public void run() {   

                        ......   

             

                        keep_running: {   

                            ......   

             

                            // second step    

                            if (loadWorkspaceFirst) {   

                                ......   

                                loadAndBindAllApps();   

                            } else {   

                                ......   

                            }   

             

                            ......   

                        }   

             

                        ......   

                    }   

             

                    ......   

                }  

             

                ...... 

            public class LauncherModel extends BroadcastReceiver {

            ......

             

            private LoaderTask mLoaderTask;

             

            private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");

            static {

            sWorkerThread.start();

            }

            private static final Handler sWorker = new Handler(sWorkerThread.getLooper());

             

            ......

             

            public void startLoader(Context context, boolean isLaunching) { 

            ...... 

             

            synchronized (mLock) { 

            ...... 

             

            // Don't bother to start the thread if we know it's not going to do anything 

            if (mCallbacks != null && mCallbacks.get() != null) { 

            ......

             

            mLoaderTask = new LoaderTask(context, isLaunching); 

            sWorker.post(mLoaderTask); 

             

            ......

             

            private class LoaderTask implements Runnable { 

            ...... 

             

            public void run() { 

            ...... 

             

            keep_running: { 

            ...... 

             

            // second step 

            if (loadWorkspaceFirst) { 

            ...... 

            loadAndBindAllApps(); 

            } else { 

            ...... 

             

            ...... 

             

            ...... 

             

            ...... 

            }

             

            ......

            }        在這個LauncherModel類中,首先創建了一個HandlerThread對象:

             

             

            view plaincopy to clipboardprint?private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader"); 

            private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");        接著調用它的start成員函數來啟動一個子線程:

             

             

            view plaincopy to clipboardprint?static { 

                sWorkerThread.start(); 

            static {

                sWorkerThread.start();

            }        接著還通過這個HandlerThread對象的getLooper函數來獲得這個子線程中的消息循環對象,并且使用這個消息循環創建對象來創建一個Handler:

             

             

            view plaincopy to clipboardprint?private static final Handler sWorker = new Handler(sWorkerThread.getLooper()); 

            private static final Handler sWorker = new Handler(sWorkerThread.getLooper());        有了這個Handler對象sWorker之后,我們就可以往這個子線程中發送消息,然后在處理這個消息的時候執行加載系統中已經安裝的應用程序的任務 了,在startLoader函數中:

             

             

            view plaincopy to clipboardprint?mLoaderTask = new LoaderTask(context, isLaunching);   

            sWorker.post(mLoaderTask);   

            mLoaderTask = new LoaderTask(context, isLaunching); 

            sWorker.post(mLoaderTask);          這里的mLoaderTask是一個LoaderTask對象,它實現了Runnable接口,因此,可以把這個LoaderTask對象作為參數傳給 sWorker.post函數。在sWorker.post函數里面,會把這個LoaderTask對象封裝成一個消息,并且放入這個子線程的消息隊列中 去。當這個子線程的消息循環處理這個消息的時候,就會調用這個LoaderTask對象的run函數,因此,我們就可以在LoaderTask對象的 run函數中通過調用loadAndBindAllApps來執行加載系統中已經安裝的應用程序的任務了。

             

                    了解了HanderThread類的使用方法之后,我們就可以重點地來分析它的實現了:

             

             

            view plaincopy to clipboardprint?public class HandlerThread extends Thread { 

                ...... 

                private Looper mLooper; 

             

                public HandlerThread(String name) { 

                    super(name); 

                    ...... 

                } 

             

                ...... 

             

                public void run() { 

                    ...... 

                    Looper.prepare(); 

                    synchronized (this) { 

                        mLooper = Looper.myLooper(); 

                        ...... 

                    } 

                    ...... 

                    Looper.loop(); 

                    ...... 

                } 

             

                public Looper getLooper() { 

                    ...... 

                    return mLooper; 

                } 

             

                ...... 

            public class HandlerThread extends Thread {

            ......

            private Looper mLooper;

             

            public HandlerThread(String name) {

            super(name);

            ......

            }

             

            ......

             

            public void run() {

            ......

            Looper.prepare();

            synchronized (this) {

            mLooper = Looper.myLooper();

            ......

            }

            ......

            Looper.loop();

            ......

            }

             

            public Looper getLooper() {

            ......

            return mLooper;

            }

             

            ......

            }        首先我們看到的是,Handler類繼承了Thread類,因此,通過它可以在應用程序中創建一個子線程,其次我們看到在它的run函數中,會進入一個消息循環中,因此,這個子線程可以常駐在應用程序中,直到它接收收到一個退出消息為止。

             

                    在run函數中,首先是調用Looper類的靜態成員函數prepare來準備一個消息循環對象:

             

             

            view plaincopy to clipboardprint?Looper.prepare(); 

            Looper.prepare();        然后通過Looper類的myLooper成員函數將這個子線程中的消息循環對象保存在HandlerThread類中的成員變量mLooper中:

             

             

            view plaincopy to clipboardprint?mLooper = Looper.myLooper(); 

            mLooper = Looper.myLooper();        這樣,其它地方就可以方便地通過它的getLooper函數來獲得這個消息循環對象了,有了這個消息循環對象后,就可以往這個子線程的消息隊列中發送消息,通知這個子線程執行特定的任務了。

             

                    最在這個run函數通過Looper類的loop函數進入消息循環中:

             

             

            view plaincopy to clipboardprint?Looper.loop(); 

            Looper.loop();        這樣,一個具有消息循環的應用程序子線程就準備就緒了。

             

                    HandlerThread類的實現雖然非常簡單,當然這得益于Java提供的Thread類和Android自己本身提供的Looper類,但是它的想法卻非常周到,為應用程序開發人員提供了很大的方便。

                    3. 需要與UI交互的應用程序子線程消息模型

             

             

                    前面說過,我們開發應用程序的時候,經常中需要創建一個子線程來在后臺執行一個特定的計算任務,而在這個任務計算的過程中,需要不斷地將計算進度或者計算 結果展現在應用程序的界面中。典型的例子是從網上下載文件,為了不阻塞應用程序的主線程,我們開辟一個子線程來執行下載任務,子線程在下載的同時不斷地將 下載進度在應用程序界面上顯示出來,這樣做出來程序就非常友好。由于子線程不能直接操作應用程序的UI,因此,這時候,我們就可以通過往應用程序的主線程 中發送消息來通知應用程序主線程更新界面上的下載進度。因為類似的這種情景在實際開發中經常碰到,Android系統為開發人員提供了一個異步任務類 (AsyncTask)來實現上面所說的功能,即它會在一個子線程中執行計算任務,同時通過主線程的消息循環來獲得更新應用程序界面的機會。

             

                    為了更好地分析AsyncTask的實現,我們先舉一個例子來說明它的用法。在前面一篇文章Android系統中的廣播(Broadcast)機制簡要介 紹和學習計劃中,我們開發了一個應用程序Broadcast,其中使用了AsyncTask來在一個線程在后臺在執行計數任務,計數過程通過廣播 (Broadcast)來將中間結果在應用程序界面上顯示出來。在這個例子中,使用廣播來在應用程序主線程和子線程中傳遞數據不是最優的方法,當時只是為 了分析Android系統的廣播機制而有意為之的。在本節內容中,我們稍微這個例子作一個簡單的修改,就可以通過消息的方式來將計數過程的中間結果在應用 程序界面上顯示出來。

             

                    為了區別Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃一文中使用的應用程序Broadcast,我們將本節中使用的應用程序 命名為Counter。首先在Android源代碼工程中創建一個Android應用程序工程,名字就為Counter,放在 packages/experimental目錄下。關于如何獲得Android源代碼工程,請參考在Ubuntu上下載、編譯和安裝Android最新 源代碼一文;關于如何在Android源代碼工程中創建應用程序工程,請參考在Ubuntu上為Android系統內置Java應用程序測試 Application Frameworks層的硬件服務一文。這個應用程序工程定義了一個名為shy.luo.counter的package,這個例子的源代碼主要就是實現 在這個目錄下的Counter.java文件中:

             

             

            view plaincopy to clipboardprint?package shy.luo.counter; 

             

            import android.app.Activity; 

            import android.content.ComponentName; 

            import android.content.Context; 

            import android.content.Intent; 

            import android.content.IntentFilter; 

            import android.os.Bundle; 

            import android.os.AsyncTask; 

            import android.util.Log; 

            import android.view.View; 

            import android.view.View.OnClickListener; 

            import android.widget.Button; 

            import android.widget.TextView; 

             

            public class Counter extends Activity implements OnClickListener { 

                private final static String LOG_TAG = "shy.luo.counter.Counter"; 

             

                private Button startButton = null; 

                private Button stopButton = null; 

                private TextView counterText = null; 

             

                private AsyncTask<Integer, Integer, Integer> task = null; 

                private boolean stop = false; 

             

                @Override 

                public void onCreate(Bundle savedInstanceState) { 

                    super.onCreate(savedInstanceState); 

                    setContentView(R.layout.main); 

             

                    startButton = (Button)findViewById(R.id.button_start); 

                    stopButton = (Button)findViewById(R.id.button_stop); 

                    counterText = (TextView)findViewById(R.id.textview_counter); 

             

                    startButton.setOnClickListener(this); 

                    stopButton.setOnClickListener(this); 

             

                    startButton.setEnabled(true); 

                    stopButton.setEnabled(false); 

             

              

                    Log.i(LOG_TAG, "Main Activity Created."); 

                } 

             

             

                @Override 

                public void onClick(View v) { 

                    if(v.equals(startButton)) { 

                        if(task == null) { 

                            task = new CounterTask(); 

                            task.execute(0); 

             

                            startButton.setEnabled(false); 

                            stopButton.setEnabled(true); 

                        } 

                    } else if(v.equals(stopButton)) { 

                        if(task != null) { 

                            stop = true; 

                            task = null; 

             

                            startButton.setEnabled(true); 

                            stopButton.setEnabled(false); 

                        } 

                    } 

                } 

             

                class CounterTask extends AsyncTask<Integer, Integer, Integer> { 

                    @Override 

                    protected Integer doInBackground(Integer... vals) { 

                        Integer initCounter = vals[0]; 

             

                        stop = false; 

                        while(!stop) { 

                            publishProgress(initCounter); 

             

                            try { 

                                Thread.sleep(1000); 

                            } catch (InterruptedException e) { 

                                e.printStackTrace(); 

                            } 

             

                            initCounter++; 

                        } 

             

                        return initCounter; 

                    } 

             

                    @Override 

                    protected void onProgressUpdate(Integer... values) { 

                        super.onProgressUpdate(values); 

             

                        String text = values[0].toString(); 

                        counterText.setText(text); 

                    } 

             

                    @Override 

                    protected void onPostExecute(Integer val) { 

                        String text = val.toString(); 

                        counterText.setText(text); 

                    } 

                }; 

            package shy.luo.counter;

             

            import android.app.Activity;

            import android.content.ComponentName;

            import android.content.Context;

            import android.content.Intent;

            import android.content.IntentFilter;

            import android.os.Bundle;

            import android.os.AsyncTask;

            import android.util.Log;

            import android.view.View;

            import android.view.View.OnClickListener;

            import android.widget.Button;

            import android.widget.TextView;

             

            public class Counter extends Activity implements OnClickListener {

            private final static String LOG_TAG = "shy.luo.counter.Counter";

             

            private Button startButton = null;

            private Button stopButton = null;

            private TextView counterText = null;

             

            private AsyncTask<Integer, Integer, Integer> task = null;

            private boolean stop = false;

             

            @Override

            public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

             

            startButton = (Button)findViewById(R.id.button_start);

            stopButton = (Button)findViewById(R.id.button_stop);

            counterText = (TextView)findViewById(R.id.textview_counter);

             

            startButton.setOnClickListener(this);

            stopButton.setOnClickListener(this);

             

            startButton.setEnabled(true);

            stopButton.setEnabled(false);

             

             

            Log.i(LOG_TAG, "Main Activity Created.");

            }

             

             

            @Override

            public void onClick(View v) {

            if(v.equals(startButton)) {

            if(task == null) {

            task = new CounterTask();

            task.execute(0);

             

            startButton.setEnabled(false);

            stopButton.setEnabled(true);

            }

            } else if(v.equals(stopButton)) {

            if(task != null) {

            stop = true;

            task = null;

             

            startButton.setEnabled(true);

            stopButton.setEnabled(false);

            }

            }

            }

             

            class CounterTask extends AsyncTask<Integer, Integer, Integer> {

            @Override

            protected Integer doInBackground(Integer... vals) {

            Integer initCounter = vals[0];

             

            stop = false;

            while(!stop) {

            publishProgress(initCounter);

             

            try {

            Thread.sleep(1000);

            } catch (InterruptedException e) {

            e.printStackTrace();

            }

             

            initCounter++;

            }

             

            return initCounter;

            }

             

            @Override

            protected void onProgressUpdate(Integer... values) {

            super.onProgressUpdate(values);

             

            String text = values[0].toString();

            counterText.setText(text);

            }

             

            @Override

            protected void onPostExecute(Integer val) {

            String text = val.toString();

            counterText.setText(text);

            }

            };

            }        這個計數器程序很簡單,它在界面上有兩個按鈕Start和Stop。點擊Start按鈕時,便會創建一個CounterTask實例task,然后調用它 的execute函數就可以在應用程序中啟動一個子線程,并且通過調用這個CounterTask類的doInBackground函數來執行計數任務。 在計數的過程中,會通過調用publishProgress函數來將中間結果傳遞到onProgressUpdate函數中去,在 onProgressUpdate函數中,就可以把中間結果顯示在應用程序界面了。點擊Stop按鈕時,便會通過設置變量stop為true,這 樣,CounterTask類的doInBackground函數便會退出循環,然后將結果返回到onPostExecute函數中去,在 onPostExecute函數,會把最終計數結果顯示在用程序界面中。

             

                   在這個例子中,我們需要注意的是:

             

                   A. CounterTask類繼承于AsyncTask類,因此它也是一個異步任務類;

             

                   B. CounterTask類的doInBackground函數是在后臺的子線程中運行的,這時候它不可以操作應用程序的界面;

             

                   C. CounterTask類的onProgressUpdate和onPostExecute兩個函數是應用程序的主線程中執行,它們可以操作應用程序的界面。

             

                   關于C這一點的實現原理,我們在后面會分析到,這里我們先完整地介紹這個例子,以便讀者可以參考做一下實驗。

             

                   接下來我們再看看應用程序的配置文件AndroidManifest.xml:

             

             

            view plaincopy to clipboardprint?<?xml version="1.0" encoding="utf-8"?> 

            <manifest xmlns:android="http://schemas.android.com/apk/res/android" 

                  package="shy.luo.counter" 

                  android:versionCode="1" 

                  android:versionName="1.0"> 

                <application android:icon="@drawable/icon" android:label="@string/app_name"> 

                    <activity android:name=".Counter" 

                              android:label="@string/app_name"> 

                        <intent-filter> 

                            <action android:name="android.intent.action.MAIN" /> 

                            <category android:name="android.intent.category.LAUNCHER" /> 

                        </intent-filter> 

                    </activity> 

                </application> 

            </manifest> 

            <?xml version="1.0" encoding="utf-8"?>

            <manifest xmlns:android="http://schemas.android.com/apk/res/android"

                  package="shy.luo.counter"

                  android:versionCode="1"

                  android:versionName="1.0">

                <application android:icon="@drawable/icon" android:label="@string/app_name">

                    <activity android:name=".Counter"

                              android:label="@string/app_name">

                        <intent-filter>

                            <action android:name="android.intent.action.MAIN" />

                            <category android:name="android.intent.category.LAUNCHER" />

                        </intent-filter>

                    </activity>

                </application>

            </manifest>       這個配置文件很簡單,我們就不介紹了。

             

                   再來看應用程序的界面文件,它定義在res/layout/main.xml文件中:

             

             

            view plaincopy to clipboardprint?<?xml version="1.0" encoding="utf-8"?>   

            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   

                android:orientation="vertical"   

                android:layout_width="fill_parent"   

                android:layout_height="fill_parent"    

                android:gravity="center">   

                <LinearLayout   

                    android:layout_width="fill_parent"   

                    android:layout_height="wrap_content"   

                    android:layout_marginBottom="10px"   

                    android:orientation="horizontal"    

                    android:gravity="center">   

                    <TextView     

                    android:layout_width="wrap_content"    

                        android:layout_height="wrap_content"    

                        android:layout_marginRight="4px"   

                        android:gravity="center"   

                        android:text="@string/counter">   

                    </TextView>   

                    <TextView     

                        android:id="@+id/textview_counter"   

                    android:layout_width="wrap_content"    

                        android:layout_height="wrap_content"    

                        android:gravity="center"   

                        android:text="0">   

                    </TextView>   

                </LinearLayout>   

                <LinearLayout   

                    android:layout_width="fill_parent"   

                    android:layout_height="wrap_content"   

                    android:orientation="horizontal"    

                    android:gravity="center">   

                    <Button    

                        android:id="@+id/button_start"   

                        android:layout_width="wrap_content"   

                        android:layout_height="wrap_content"   

                        android:gravity="center"   

                        android:text="@string/start">   

                    </Button>   

                    <Button    

                        android:id="@+id/button_stop"   

                        android:layout_width="wrap_content"   

                        android:layout_height="wrap_content"   

                        android:gravity="center"   

                        android:text="@string/stop" >   

                    </Button>    

                 </LinearLayout>     

            </LinearLayout>   

            <?xml version="1.0" encoding="utf-8"?> 

            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 

                android:orientation="vertical" 

                android:layout_width="fill_parent" 

                android:layout_height="fill_parent"  

                android:gravity="center"> 

                <LinearLayout 

                    android:layout_width="fill_parent" 

                    android:layout_height="wrap_content" 

                    android:layout_marginBottom="10px" 

                    android:orientation="horizontal"  

                    android:gravity="center"> 

                    <TextView   

                    android:layout_width="wrap_content"  

                        android:layout_height="wrap_content"  

                        android:layout_marginRight="4px" 

                        android:gravity="center" 

                        android:text="@string/counter"> 

                    </TextView> 

                    <TextView   

                        android:id="@+id/textview_counter" 

                    android:layout_width="wrap_content"  

                        android:layout_height="wrap_content"  

                        android:gravity="center" 

                        android:text="0"> 

                    </TextView> 

                </LinearLayout> 

                <LinearLayout 

                    android:layout_width="fill_parent" 

                    android:layout_height="wrap_content" 

                    android:orientation="horizontal"  

                    android:gravity="center"> 

                    <Button  

                        android:id="@+id/button_start" 

                        android:layout_width="wrap_content" 

                        android:layout_height="wrap_content" 

                        android:gravity="center" 

                        android:text="@string/start"> 

                    </Button> 

                    <Button  

                        android:id="@+id/button_stop" 

                        android:layout_width="wrap_content" 

                        android:layout_height="wrap_content" 

                        android:gravity="center" 

                        android:text="@string/stop" > 

                    </Button> 

                 </LinearLayout>   

            </LinearLayout>         這個界面配置文件也很簡單,等一下我們在模擬器把這個應用程序啟動起來后,就可以看到它的截圖了。

             

                   應用程序用到的字符串資源文件位于res/values/strings.xml文件中:

             

             

            view plaincopy to clipboardprint?<?xml version="1.0" encoding="utf-8"?>   

            <resources>   

                <string name="app_name">Counter</string>   

                <string name="counter">Counter: </string>   

                <string name="start">Start Counter</string>   

                <string name="stop">Stop Counter</string>   

            </resources>  

            <?xml version="1.0" encoding="utf-8"?> 

            <resources> 

                <string name="app_name">Counter</string> 

                <string name="counter">Counter: </string> 

                <string name="start">Start Counter</string> 

                <string name="stop">Stop Counter</string> 

            </resources>        最后,我們還要在工程目錄下放置一個編譯腳本文件Android.mk:

             

             

            view plaincopy to clipboardprint?LOCAL_PATH:= $(call my-dir)         

            include $(CLEAR_VARS)         

                     

            LOCAL_MODULE_TAGS := optional         

                     

            LOCAL_SRC_FILES := $(call all-subdir-java-files)         

                     

            LOCAL_PACKAGE_NAME := Counter         

                     

            include $(BUILD_PACKAGE)   

            LOCAL_PATH:= $(call my-dir)       

            include $(CLEAR_VARS)       

                   

            LOCAL_MODULE_TAGS := optional       

                   

            LOCAL_SRC_FILES := $(call all-subdir-java-files)       

                   

            LOCAL_PACKAGE_NAME := Counter       

                   

            include $(BUILD_PACKAGE)         接下來就要編譯了。有關如何單獨編譯Android源代碼工程的模塊,以及如何打包system.img,請參考如何單獨編譯Android源代碼中的模塊一文。

                   執行以下命令進行編譯和打包:

             

             

            view plaincopy to clipboardprint?USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Counter           

            USER-NAME@MACHINE-NAME:~/Android$ make snod 

            USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Counter         

            USER-NAME@MACHINE-NAME:~/Android$ make snod       這樣,打包好的Android系統鏡像文件system.img就包含我們前面創建的Counter應用程序了。

                   再接下來,就是運行模擬器來運行我們的例子了。關于如何在Android源代碼工程中運行模擬器,請參考在Ubuntu上下載、編譯和安裝Android最新源代碼一文。

                   執行以下命令啟動模擬器:

            view plaincopy to clipboardprint?USER-NAME@MACHINE-NAME:~/Android$ emulator  

            USER-NAME@MACHINE-NAME:~/Android$ emulator        最后我們就可以在Launcher中找到Counter應用程序圖標,把它啟動起來,點擊Start按鈕,就會看到應用程序界面上的計數器跑起來了:

             

             

             

             

                    這樣,使用AsyncTask的例子就介紹完了,下面,我們就要根據上面對AsyncTask的使用情況來重點分析它的實現了。

             

                    AsyncTask類定義在frameworks/base/core/java/android/os/AsyncTask.java文件中:

             

             

            view plaincopy to clipboardprint?public abstract class AsyncTask<Params, Progress, Result> { 

                ...... 

             

                private static final BlockingQueue<Runnable> sWorkQueue = 

                        new LinkedBlockingQueue<Runnable>(10); 

             

                private static final ThreadFactory sThreadFactory = new ThreadFactory() { 

                    private final AtomicInteger mCount = new AtomicInteger(1); 

             

                    public Thread newThread(Runnable r) { 

                        return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); 

                    } 

                }; 

             

                ...... 

             

                private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, 

                    MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory); 

             

                private static final int MESSAGE_POST_RESULT = 0x1; 

                private static final int MESSAGE_POST_PROGRESS = 0x2; 

                private static final int MESSAGE_POST_CANCEL = 0x3; 

             

                private static final InternalHandler sHandler = new InternalHandler(); 

             

                private final WorkerRunnable<Params, Result> mWorker; 

                private final FutureTask<Result> mFuture; 

             

                ...... 

             

                public AsyncTask() { 

                    mWorker = new WorkerRunnable<Params, Result>() { 

                        public Result call() throws Exception { 

                            ...... 

                            return doInBackground(mParams); 

                        } 

                    }; 

             

                    mFuture = new FutureTask<Result>(mWorker) { 

                        @Override 

                        protected void done() { 

                            Message message; 

                            Result result = null; 

             

                            try { 

                                result = get(); 

                            } catch (InterruptedException e) { 

                                android.util.Log.w(LOG_TAG, e); 

                            } catch (ExecutionException e) { 

                                throw new RuntimeException("An error occured while executing doInBackground()", 

                                    e.getCause()); 

                            } catch (CancellationException e) { 

                                message = sHandler.obtainMessage(MESSAGE_POST_CANCEL, 

                                    new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null)); 

                                message.sendToTarget(); 

                                return; 

                            } catch (Throwable t) { 

                                throw new RuntimeException("An error occured while executing " 

                                    + "doInBackground()", t); 

                            } 

             

                            message = sHandler.obtainMessage(MESSAGE_POST_RESULT, 

                                new AsyncTaskResult<Result>(AsyncTask.this, result)); 

                            message.sendToTarget(); 

                        } 

                    }; 

                } 

             

                ...... 

             

                public final Result get() throws InterruptedException, ExecutionException { 

                    return mFuture.get(); 

                } 

             

                ...... 

             

                public final AsyncTask<Params, Progress, Result> execute(Params... params) { 

                    ...... 

             

                    mWorker.mParams = params; 

                    sExecutor.execute(mFuture); 

             

                    return this; 

                } 

             

                ...... 

             

                protected final void publishProgress(Progress... values) { 

                    sHandler.obtainMessage(MESSAGE_POST_PROGRESS, 

                        new AsyncTaskResult<Progress>(this, values)).sendToTarget(); 

                } 

             

                    private void finish(Result result) { 

                            ...... 

                            onPostExecute(result); 

                            ...... 

                    } 

             

                ...... 

             

                private static class InternalHandler extends Handler { 

                    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) 

                    @Override 

                    public void handleMessage(Message msg) { 

                        AsyncTaskResult result = (AsyncTaskResult) msg.obj; 

                        switch (msg.what) { 

                            case MESSAGE_POST_RESULT: 

                             // There is only one result  

                             result.mTask.finish(result.mData[0]); 

                             break; 

                            case MESSAGE_POST_PROGRESS: 

                             result.mTask.onProgressUpdate(result.mData); 

                             break; 

                            case MESSAGE_POST_CANCEL: 

                             result.mTask.onCancelled(); 

                             break; 

                        } 

                    } 

                } 

             

                private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { 

                    Params[] mParams; 

                } 

             

                private static class AsyncTaskResult<Data> { 

                    final AsyncTask mTask; 

                    final Data[] mData; 

             

                    AsyncTaskResult(AsyncTask task, Data... data) { 

                        mTask = task; 

                        mData = data; 

                    } 

                } 

            public abstract class AsyncTask<Params, Progress, Result> {

            ......

             

            private static final BlockingQueue<Runnable> sWorkQueue =

            new LinkedBlockingQueue<Runnable>(10);

             

            private static final ThreadFactory sThreadFactory = new ThreadFactory() {

            private final AtomicInteger mCount = new AtomicInteger(1);

             

            public Thread newThread(Runnable r) {

            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());

            }

            };

             

            ......

             

            private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,

            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);

             

            private static final int MESSAGE_POST_RESULT = 0x1;

            private static final int MESSAGE_POST_PROGRESS = 0x2;

            private static final int MESSAGE_POST_CANCEL = 0x3;

             

            private static final InternalHandler sHandler = new InternalHandler();

             

            private final WorkerRunnable<Params, Result> mWorker;

            private final FutureTask<Result> mFuture;

             

            ......

             

            public AsyncTask() {

            mWorker = new WorkerRunnable<Params, Result>() {

            public Result call() throws Exception {

            ......

            return doInBackground(mParams);

            }

            };

             

            mFuture = new FutureTask<Result>(mWorker) {

            @Override

            protected void done() {

            Message message;

            Result result = null;

             

            try {

            result = get();

            } catch (InterruptedException e) {

            android.util.Log.w(LOG_TAG, e);

            } catch (ExecutionException e) {

            throw new RuntimeException("An error occured while executing doInBackground()",

            e.getCause());

            } catch (CancellationException e) {

            message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,

            new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));

            message.sendToTarget();

            return;

            } catch (Throwable t) {

            throw new RuntimeException("An error occured while executing "

            + "doInBackground()", t);

            }

             

            message = sHandler.obtainMessage(MESSAGE_POST_RESULT,

            new AsyncTaskResult<Result>(AsyncTask.this, result));

            message.sendToTarget();

            }

            };

            }

             

            ......

             

            public final Result get() throws InterruptedException, ExecutionException {

            return mFuture.get();

            }

             

            ......

             

            public final AsyncTask<Params, Progress, Result> execute(Params... params) {

            ......

             

            mWorker.mParams = params;

            sExecutor.execute(mFuture);

             

            return this;

            }

             

            ......

             

            protected final void publishProgress(Progress... values) {

            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,

            new AsyncTaskResult<Progress>(this, values)).sendToTarget();

            }

             

                    private void finish(Result result) {

                            ......

                            onPostExecute(result);

                            ......

                    }

             

            ......

             

            private static class InternalHandler extends Handler {

            @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})

            @Override

            public void handleMessage(Message msg) {

            AsyncTaskResult result = (AsyncTaskResult) msg.obj;

            switch (msg.what) {

                    case MESSAGE_POST_RESULT:

                 // There is only one result

                 result.mTask.finish(result.mData[0]);

                 break;

                    case MESSAGE_POST_PROGRESS:

                 result.mTask.onProgressUpdate(result.mData);

                 break;

                    case MESSAGE_POST_CANCEL:

                 result.mTask.onCancelled();

                 break;

            }

            }

            }

             

            private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {

            Params[] mParams;

            }

             

            private static class AsyncTaskResult<Data> {

            final AsyncTask mTask;

            final Data[] mData;

             

            AsyncTaskResult(AsyncTask task, Data... data) {

            mTask = task;

            mData = data;

            }

            }

            }

                    從AsyncTask的實現可以看出,當我們第一次創建一個AsyncTask對象時,首先會執行下面靜態初始化代碼創建一個線程池sExecutor:

             

             

            view plaincopy to clipboardprint?private static final BlockingQueue<Runnable> sWorkQueue = 

                new LinkedBlockingQueue<Runnable>(10); 

             

            private static final ThreadFactory sThreadFactory = new ThreadFactory() { 

                private final AtomicInteger mCount = new AtomicInteger(1); 

             

                public Thread newThread(Runnable r) { 

                    return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); 

                } 

            }; 

             

            ...... 

             

            private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, 

                MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory); 

            private static final BlockingQueue<Runnable> sWorkQueue =

            new LinkedBlockingQueue<Runnable>(10);

             

            private static final ThreadFactory sThreadFactory = new ThreadFactory() {

            private final AtomicInteger mCount = new AtomicInteger(1);

             

            public Thread newThread(Runnable r) {

            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());

            }

            };

             

            ......

             

            private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,

            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);        這里的ThreadPoolExecutor是Java提供的多線程機制之一,這里用的構造函數原型為:

             

             

            view plaincopy to clipboardprint?ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,  

                BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) 

            ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,

                BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)        各個參數的意義如下:

             

                    corePoolSize -- 線程池的核心線程數量

             

                    maximumPoolSize -- 線程池的最大線程數量

             

                    keepAliveTime -- 若線程池的線程數數量大于核心線程數量,那么空閑時間超過keepAliveTime的線程將被回收

             

                    unit -- 參數keepAliveTime使用的時間單位

             

                    workerQueue -- 工作任務隊列

             

                    threadFactory -- 用來創建線程池中的線程

                    簡單來說,ThreadPoolExecutor的運行機制是這樣的:每一個工作任務用一個Runnable對象來表示,當我們要把一個工作任務交給這個 線程池來執行的時候,就通過調用ThreadPoolExecutor的execute函數來把這個工作任務加入到線程池中去。此時,如果線程池中的線程 數量小于corePoolSize,那么就會調用threadFactory接口來創建一個新的線程并且加入到線程池中去,再執行這個工作任務;如果線程 池中的線程數量等于corePoolSize,但是工作任務隊列workerQueue未滿,則把這個工作任務加入到工作任務隊列中去等待執行;如果線程 池中的線程數量大于corePoolSize,但是小于maximumPoolSize,并且工作任務隊列workerQueue已經滿了,那么就會調用 threadFactory接口來創建一個新的線程并且加入到線程池中去,再執行這個工作任務;如果線程池中的線程量已經等于 maximumPoolSize了,并且工作任務隊列workerQueue也已經滿了,這個工作任務就被拒絕執行了。

             

                    創建好了線程池后,再創建一個消息處理器:

             

             

            view plaincopy to clipboardprint?private static final InternalHandler sHandler = new InternalHandler(); 

            private static final InternalHandler sHandler = new InternalHandler();        注意,這行代碼是在應用程序的主線程中執行的,因此,這個消息處理器sHandler內部引用的消息循環對象looper是應用程序主線程的消息循環對 象,消息處理器的實現機制具體可以參考前面一篇文章Android應用程序消息處理機制(Looper、Handler)分析。

             

                    AsyncTask類的靜態初始化代碼執行完成之后,才開始創建AsyncTask對象,即執行AsyncTask類的構造函數:

             

             

            view plaincopy to clipboardprint?public AsyncTask() { 

                mWorker = new WorkerRunnable<Params, Result>() { 

                    public Result call() throws Exception { 

                        ...... 

                        return doInBackground(mParams); 

                    } 

                }; 

             

                mFuture = new FutureTask<Result>(mWorker) { 

                    @Override 

                    protected void done() { 

                        Message message; 

                        Result result = null; 

             

                        try { 

                            result = get(); 

                        } catch (InterruptedException e) { 

                            android.util.Log.w(LOG_TAG, e); 

                        } catch (ExecutionException e) { 

                            throw new RuntimeException("An error occured while executing doInBackground()", 

                                e.getCause()); 

                        } catch (CancellationException e) { 

                            message = sHandler.obtainMessage(MESSAGE_POST_CANCEL, 

                                new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null)); 

                            message.sendToTarget(); 

                            return; 

                        } catch (Throwable t) { 

                            throw new RuntimeException("An error occured while executing " 

                                + "doInBackground()", t); 

                        } 

             

                        message = sHandler.obtainMessage(MESSAGE_POST_RESULT, 

                            new AsyncTaskResult<Result>(AsyncTask.this, result)); 

                        message.sendToTarget(); 

                    } 

                }; 

            public AsyncTask() {

            mWorker = new WorkerRunnable<Params, Result>() {

            public Result call() throws Exception {

            ......

            return doInBackground(mParams);

            }

            };

             

            mFuture = new FutureTask<Result>(mWorker) {

            @Override

            protected void done() {

            Message message;

            Result result = null;

             

            try {

            result = get();

            } catch (InterruptedException e) {

            android.util.Log.w(LOG_TAG, e);

            } catch (ExecutionException e) {

            throw new RuntimeException("An error occured while executing doInBackground()",

            e.getCause());

            } catch (CancellationException e) {

            message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,

            new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));

            message.sendToTarget();

            return;

            } catch (Throwable t) {

            throw new RuntimeException("An error occured while executing "

            + "doInBackground()", t);

            }

             

            message = sHandler.obtainMessage(MESSAGE_POST_RESULT,

            new AsyncTaskResult<Result>(AsyncTask.this, result));

            message.sendToTarget();

            }

            };

            }        在AsyncTask類的構造函數里面,主要是創建了兩個對象,分別是一個WorkerRunnable對象mWorker和一個FutureTask對象mFuture。

             

                    WorkerRunnable類實現了Runnable接口,此外,它的內部成員變量mParams用于保存從AsyncTask對象的execute函數傳進來的參數列表:

             

             

            view plaincopy to clipboardprint?private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { 

                Params[] mParams; 

            private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {

            Params[] mParams;

            }        FutureTask類也實現了Runnable接口,所以它可以作為一個工作任務通過調用AsyncTask類的execute函數添加到sExecuto線程池中去:

             

             

            view plaincopy to clipboardprint?public final AsyncTask<Params, Progress, Result> execute(Params... params) { 

                ...... 

             

                mWorker.mParams = params; 

                sExecutor.execute(mFuture); 

             

                return this; 

            public final AsyncTask<Params, Progress, Result> execute(Params... params) {

            ......

             

            mWorker.mParams = params;

            sExecutor.execute(mFuture);

             

            return this;

            }

             

                   這里的FutureTask對象mFuture是用來封裝前面的WorkerRunnable對象mWorker。當mFuture加入到線程池中執行時,它調用的是mWorker對象的call函數:

             

             

            view plaincopy to clipboardprint?mWorker = new WorkerRunnable<Params, Result>() { 

                public Result call() throws Exception { 

                       ...... 

                       return doInBackground(mParams); 

                    } 

            }; 

            mWorker = new WorkerRunnable<Params, Result>() {

            public Result call() throws Exception {

                   ......

                   return doInBackground(mParams);

                    }

            };        在call函數里面,會調用AsyncTask類的doInBackground函數來執行真正的任務,這個函數是要由AsyncTask的子類來實現的,注意,這個函數是在應用程序的子線程中執行的,它不可以操作應用程序的界面。

             

             

                    我們可以通過mFuture對象來操作當前執行的任務,例如查詢當前任務的狀態,它是正在執行中,還是完成了,還是被取消了,如果是完成了,還可以通過它獲得任務的執行結果,如果還沒有完成,可以取消任務的執行。

             

                    當工作任務mWorker執行完成的時候,mFuture對象中的done函數就會被被調用,根據任務的完成狀況,執行相應的操作,例如,如果是因為異常 而完成時,就會拋異常,如果是正常完成,就會把任務執行結果封裝成一個AsyncTaskResult對象:

             

             

            view plaincopy to clipboardprint?private static class AsyncTaskResult<Data> { 

                final AsyncTask mTask; 

                final Data[] mData; 

             

                AsyncTaskResult(AsyncTask task, Data... data) { 

                    mTask = task; 

                    mData = data; 

                } 

            private static class AsyncTaskResult<Data> {

            final AsyncTask mTask;

            final Data[] mData;

             

            AsyncTaskResult(AsyncTask task, Data... data) {

            mTask = task;

            mData = data;

            }

            }        其中,成員變量mData保存的是任務執行結果,而成員變量mTask指向前面我們創建的AsyncTask對象。

                    最后把這個AsyncTaskResult對象封裝成一個消息,并且通過消息處理器sHandler加入到應用程序主線程的消息隊列中:

             

             

            view plaincopy to clipboardprint?message = sHandler.obtainMessage(MESSAGE_POST_RESULT, 

                new AsyncTaskResult<Result>(AsyncTask.this, result)); 

            message.sendToTarget(); 

            message = sHandler.obtainMessage(MESSAGE_POST_RESULT,

            new AsyncTaskResult<Result>(AsyncTask.this, result));

            message.sendToTarget();        這個消息最終就會在InternalHandler類的handleMessage函數中處理了:

             

             

            view plaincopy to clipboardprint?private static class InternalHandler extends Handler { 

                @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) 

                @Override 

                public void handleMessage(Message msg) { 

                    AsyncTaskResult result = (AsyncTaskResult) msg.obj; 

                    switch (msg.what) { 

                    case MESSAGE_POST_RESULT: 

                        // There is only one result  

                        result.mTask.finish(result.mData[0]); 

                        break; 

                    ...... 

                    } 

                } 

            private static class InternalHandler extends Handler {

            @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})

            @Override

            public void handleMessage(Message msg) {

            AsyncTaskResult result = (AsyncTaskResult) msg.obj;

            switch (msg.what) {

            case MESSAGE_POST_RESULT:

            // There is only one result

            result.mTask.finish(result.mData[0]);

            break;

            ......

            }

            }

            }        在這個函數里面,最終會調用前面創建的這個AsyncTask對象的finish函數來進一步處理:

             

             

            view plaincopy to clipboardprint?private void finish(Result result) { 

                   ...... 

                   onPostExecute(result); 

                   ...... 

            private void finish(Result result) {

                   ......

                   onPostExecute(result);

                   ......

            }        這個函數調用AsyncTask類的onPostExecute函數來進一步處理,AsyncTask類的onPostExecute函數一般是要由其子類來重載的,注意,這個函數是在應用程序的主線程中執行的,因此,它可以操作應用程序的界面。

                    在任務執行的過程當中,即執行doInBackground函數時候,可能通過調用publishProgress函數來將中間結果封裝成一個消息發送到應用程序主線程中的消息隊列中去:

             

             

            view plaincopy to clipboardprint?protected final void publishProgress(Progress... values) { 

                sHandler.obtainMessage(MESSAGE_POST_PROGRESS, 

                    new AsyncTaskResult<Progress>(this, values)).sendToTarget(); 

            protected final void publishProgress(Progress... values) {

            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,

            new AsyncTaskResult<Progress>(this, values)).sendToTarget();

            }        這個消息最終也是由InternalHandler類的handleMessage函數來處理的:

             

             

             

            view plaincopy to clipboardprint?private static class InternalHandler extends Handler { 

                @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) 

                @Override 

                public void handleMessage(Message msg) { 

                    AsyncTaskResult result = (AsyncTaskResult) msg.obj; 

                    switch (msg.what) { 

                    ...... 

                    case MESSAGE_POST_PROGRESS: 

                             result.mTask.onProgressUpdate(result.mData); 

                             break; 

                    ...... 

                    } 

                } 

            private static class InternalHandler extends Handler {

            @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})

            @Override

            public void handleMessage(Message msg) {

            AsyncTaskResult result = (AsyncTaskResult) msg.obj;

            switch (msg.what) {

            ......

            case MESSAGE_POST_PROGRESS:

                 result.mTask.onProgressUpdate(result.mData);

                 break;

            ......

            }

            }

            }        這里它調用前面創建的AsyncTask對象的onPorgressUpdate函數來進一步處理,這個函數一般是由AsyncTask的子類來實現的, 注意,這個函數是在應用程序的主線程中執行的,因此,它和前面的onPostExecute函數一樣,可以操作應用程序的界面。

             

                   這樣,AsyncTask類的主要實現就介紹完了,結合前面開發的應用程序Counter來分析,會更好地理解它的實現原理。

             

                   至此,Android應用程序線程消息循環模型就分析完成了,理解它有利于我們在開發Android應用程序時,能夠充分利用多線程的并發性來提高應用程序的性能以及獲得良好的用戶體驗。 

            posted on 2012-03-12 23:33 小果子 閱讀(1830) 評論(0)  編輯 收藏 引用 所屬分類: Android & Ios
            一97日本道伊人久久综合影院| 中文字幕日本人妻久久久免费| 99久久99这里只有免费费精品| 色婷婷综合久久久中文字幕| 精品久久久久久无码专区| 久久精品国产亚洲网站| 开心久久婷婷综合中文字幕| 午夜精品久久久久久中宇| 51久久夜色精品国产| 久久无码中文字幕东京热| 久久精品人人做人人爽电影| 伊人久久无码精品中文字幕| 国产精品久久久久久福利漫画| 亚洲国产日韩欧美综合久久| 69久久精品无码一区二区| 亚洲精品视频久久久| 国产成人精品久久亚洲| 麻豆亚洲AV永久无码精品久久| 青春久久| 久久精品国产欧美日韩| 久久99精品综合国产首页| 久久午夜无码鲁丝片| 久久99这里只有精品国产| 国产免费福利体检区久久| 69久久夜色精品国产69| 久久人人爽人人爽人人片av麻烦| 国产精品丝袜久久久久久不卡| 99久久99久久| aaa级精品久久久国产片| 久久久久亚洲AV片无码下载蜜桃 | 青草国产精品久久久久久| 伊色综合久久之综合久久| 欧美日韩成人精品久久久免费看| AA级片免费看视频久久| 精品久久久久久久久久久久久久久| 久久精品免费一区二区三区| 青青草原1769久久免费播放| 99久久精品九九亚洲精品| AA级片免费看视频久久| 久久精品无码免费不卡| 亚洲欧美日韩久久精品|