<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ### **Android中線程模型** [進程線程](http://note.youdao.com/noteshare?id=de140840a1da668b7f2f7f3facb34620) [Android多線程的四種方式](https://www.jianshu.com/p/2b634a7c49ec) [理解Android線程創建流程](http://www.hmoore.net/alex_wsc/androidsystem/483949) [ActivityThread and ApplicationThread](https://www.2cto.com/kf/201312/269075.html) [Google官網介紹DDMS](https://developer.android.com/studio/profile/monitor.html) **所有Android 應用的線程都對應一個Linux 線程**,虛擬機因而可以更多地依賴操作系統的線程調度和管理機制。不同的應用在不同的進程空間里運行,加之對不同來源的應用都使用不同的Linux用戶來運行,可以最大限度地保護應用的安全和獨立運行。 **Android線程,一般地就是指Android虛擬機線程**,而虛擬機線程是通過系統調用而創建的Linux線程。純粹的Linux線程與虛擬機線程的區別在于虛擬機線程具有運行Java代碼的runtime. **除了虛擬機線程,還有Native線程和其他線程(可以從DDMS工具查看某一進程中的所有線程)**,對于Native線程又分為是否具有訪問Java代碼的兩類線程。 #### **使用DDMS工具查看APP中進程中的線程** 如何更好地使用DDMS工具可參考以下文章 [Android Studio中怎么使用DDMS工具?](https://www.cnblogs.com/gaobig/p/5029381.html) [Android的DDMS中的Threads的各個字段的含義](http://blog.csdn.net/candyliuxj/article/details/7430056) [Android開發調試必備 - 使用DDMS](http://blog.csdn.net/stzy00/article/details/46554529) >[info] 如何驗證一個進程中的線程數目和種類? > 可以通過IDE編譯工具(eclipse或者AS)安裝一個APP到模擬器或真機,打開DDMS工具,選擇Thread菜單欄,可以看到當前進程中的線程種類和數目 **注意:下面查看的線程信息,是system_process進程中的信息,還有其他進程中信息,可以自行查看。** 運行AndroidDemo, **MainActivity.java** ~~~ public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } ~~~ **activity_main.xml** ~~~ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.wsc.androiddemo.MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout> ~~~ 打開DDMS,選擇**system_process**,查看系統進程中的線程信息。 如下圖所示: :-: ![DDMS分析App線程](https://box.kancloud.cn/4b551c7a274da38e9bbcda36d4f600ff_1173x501.jpg) 圖1:DDMS分析App線程 :-: ![主線程的信息](https://box.kancloud.cn/3ee7ed8dd3c3c2e297982ac2f5c563c8_562x561.jpg) 圖2 :主線程的信息 ![android.bg線程中的信息](https://box.kancloud.cn/e081cd07b1fa295a9f04c84acf5cd187_556x476.jpg) 圖3:android.bg線程中的信息 ![ActivityManager線程中的信息](https://box.kancloud.cn/fc1f81feef439615bf6009eab9958c45_590x480.jpg) 圖4:ActivityManager線程中的信息 類似圖4中ActivityManager線程的信息的線程還有以下system_process中的線程信息 * android.fg * android.ui * android.io * android.display * PowerManagerService * PackageManager * PackageInstaller * MountService * WifiStateMachine * NetworkStats * NetworkPolicy * Wifi2pService * WifiService * ConnectivityServiceThread * NsdService * ranker * backup * WifiWatchdogStateMachine * WifiManager * WifiScanningSerice * WifiRttService * NetWorkTimeUpdateService * NetWorkMonitorNetWorkAgentInfo * DhcpStateMachine 從上面圖4以及類似的24個線程的信息來看,除了主線程,一創建就會調用Looper類和Message Queue類的方法外,其他的線程(圖4以及類似的24個線程,以及其他的線程)也會調用,**能否得出這些線程一誕生就有一個Looper類的對象和一個MQ(Message Queue)數據結構?這還有待驗證**。 查看當前activity所在的進程中的線程的信息,如下圖5所示 :-: ![App所在進程的線程信息](https://box.kancloud.cn/3b8e66b335f13ffc222df982958ea18b_1144x596.jpg) 圖5:App所在進程的線程信息 **結論**: 1. 從上面系統進程和APP進程中線程信息來看,主線程和其他的一些線程的生命周期和它們所在的進程有關,進程被kill殺掉,那么這些線程也就不存在了;在主線程中創建的子線程的生命周期開始于start()方法,終止于run()函數運行結束。 守護線程的生命周期還和JVM有關系,當別的線程都dead時,JVM會kill掉所有守護線程然后退出。 2. 實驗:在APP主線程創建一個子線程,主線程創建一個handler,用于更新UI;在子線程有一個點擊事件,效果是更改主線程中UI的TextView文本內容改變,結果我們在DDMS中APP所在的進程中,沒有看到這個子線程的創建和消失。 **每一個進程在誕生時,都會誕生一個主線程(Main Thread),以及誕生一個Looper類的對象和一個MQ(Message Queue)數據結構**。每當主線程作完事情,就會去執行Looper類。此時,不斷地觀察MQ的動態。如下圖: **不同進程的地址空間是獨立的** :-: ![](https://box.kancloud.cn/ad7b112bb4a165c597e19e259641b5ed_484x305.jpg) 圖6:獨立的進程空間 >[info] **備注**:然而,主線程創建一個子線程時,在預設情形下,子線程并不具有自己的Looper對象和MQ。由于沒有Looper對象,就沒有信息回圈(Message Loop),一旦工作完畢了,此子線程就結束了。 > 既然沒有Looper對象也沒有MQ,也就不能接受外來的Message對象了。則別的線程就無法透過MQ來傳遞信息給它了。 那么,如果別的線程(如主線程)需要與子線程通訊時(這里的意思是主線程傳遞消息 通過handler.sendMessage給子線程),該如何呢? 答案是:替它誕生一個Looper對象和一個MQ就行了。 > 主線程被創建的時候就會默認初始化Looper,因此在主線程中默認可以使用handler,不用手動創建Looper #### **Android 的單線程模型** 當第一次啟動一個程序時, **Android 會同時啟動一個對應的主線程(Main Thread)**。**主線程主要負責處理與UI 相關的事件**,如用戶的按鍵事件,用戶接觸、屏幕的事件以及屏幕繪圖事件,并把相關的事件分發到對應的組件進行處理,所以**主線程通常又被叫作UI 線程**。 >[warning] **注意**: > * ActivityThread,不是主線程,只是運行在主線程的一個對象,從[ActivityThread.java源碼](https://www.androidos.net.cn/android/6.0.1_r16/xref/frameworks/base/core/java/android/app/ActivityThread.java)來說,它只是一個final類。 > * ApplicationThread是ActivityThread的私有內部類,也是一個Binder對象。 * * * * * * * * * * **備注**:主線程中會構造這兩個類的對象。但是**他們不是線程**,你看看繼承關系就可以知道**ApplicationThread是binder, ActivityThread是一個final類也不是真正的線程**。 如果你用ddms查看某一個進程的所有線程,你會發現它只有一個main thread,當然它可能還有binder thread, jdwp, signal catcher等。 ? 一個應用程序對應一個ActivityThread實例,應用程序由activityThread打開消息循環, 同時,一個應用程序也對應一個**ApplicationThread對象**,此對象**是ActivityThread 與 ActivityManagerService連接的橋梁**。 應該不是一個應用程序對應一個ActivityThread實例,而是一個進程對應一個ActivityThread實例,這個進程里面所有的activity對應這一個ActivityThread實例,你可以看看ActivityThread類包含了mActivities。 * * * * * * * * * * 在開發Android 應用程序時必須遵守單線程模型的原則: **Android UI 操作并不是線程安全的, 并且這些操作必須在UI 線程中執行。** 如果在非UI 線程中直接操作Ul 線程,會拋出異常。 工作線程-----要保證應用 UI 的響應能力,關鍵是不能阻塞 UI 線程。如果執行的操作不能很快完成,則應確保它們在單獨的線程(“后臺”或“工作”線程)中運行。 Android 的單線程模式必須遵守兩條規則: * 不要阻塞 UI 線程 * 不要在 UI 線程之外訪問 Android UI 工具包 由于UI 線程負責事件的監昕和繪圖處理,因此**必須保證UI 線程能夠隨時響應用戶的需求**,UI 線程里的操作應該像中斷事件那樣短小,費時的操作(如網絡連接)需要另開線程, 否則,如果UI 線程超過5 s 沒有響應用戶請求, 會彈出對話框提醒用戶終止應用程序。 如果在新開的線程中需要對Ul 線程進行設定,就可能違反單線程模型,因此**Android 采用一種復雜的Message Queue 機制保證線程間的通信。** #### **解析異步消息處理機制** 下圖就是異步消息處理機制流程示意圖 ![異步消息處理機制流程示意圖](https://box.kancloud.cn/8111247adaf48b50e8c89c430e6d9c6f_720x510.jpg) 圖7:異步消息處理機制流程示意圖 >[info] **備注**:上圖是Handler消息機制的處理流程,適用于所有的傳遞消息過程:工作線程傳遞消息給主線程,可以是主線程傳遞給工作線程,也可以是各個工作線程之間傳遞消息,還可以是主線程內部傳遞消息。 Android 中的異步消息處理主要由4 個部分組成: Message 、Handler 、MessageQueue 和Looper。 * **Message** Message 是在線程之間傳遞的消息,它可以在內部攜帶少量的信息,用于在不同線程之間交換數據。 * **Handler** Handler 顧名思義也就是處理者的意思,它主要是用于發送和處理消息的。發送消息一般是使用Handler 的sendMessage ()方法,而發出的消息經過一系列地輾轉處理后,最終會傳遞到Handler 的handleMessage ()方法中。 * **MessageQueue** MessageQqeue 是消息隊列的意思,它主要用于存放所有通過Handler 發送的消息。這部分消息會一直存在于消息隊列中,等待被處理。每個線程中只會有一個MessageQueue 對象。 * **Looper** Looper 是每個線程中的MessageQueue 的管家,調用Looper 的loop ()方法后,就會進入到一個無限循環當中,然后每當發現MessageQueue 中存在一條消息,就會將它取出,并傳遞到Handler 的handleMessage ()方法中。每個線程中也只會有一個Looper 對象。 **子線程傳遞消息給UI線程(主線程)的整體流程如下**: 首先需要在主線程當中創建一個Handler 對象,并重寫handleMessage ()方法。然后當子線程中需要進行UI 操作時,就創建一個Message 對象,并通過Handler 將這條消息發送出去。之后這條消息會被添加到MessageQueue 的隊列中等待被處理,而Looper 則會一直嘗試從MessageQueue 中取出待處理消息,最后分發回Handler 的handleMessage ()方法中。由于Handler 是在主線程中創建的,所以此時handleMessage ()方法中的代碼也會在主線程中運行,于是我們在這里就可以安心地進行UI 操作了。 示例代碼如下所示: ~~~ public class MainActivity extends AppCompatActivity implements View.OnClickListener { public static final int UPDATE_TEXT = 1; private TextView text; private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_TEXT: // 在這里可以進行UI操作 text.setText("Nice to meet you"); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text = (TextView) findViewById(R.id.text); Button changeText = (Button) findViewById(R.id.change_text); changeText.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.change_text: new Thread(new Runnable() { @Override public void run() { Message message = new Message(); message.what = UPDATE_TEXT; handler.sendMessage(message); // 將Message對象發送出去 } }).start(); break; default: break; } } } ~~~ #### **AsyncTask** 不過為了更加方便我們在子線程中對UI 進行操作, Android 還提供了另外一些好用的工具,比如AsyncTask。借助AsyncTask,即使你對異步消息處理機制完全不了解,也可以十分簡單地從子線程切換到主線程。當然, AsyncTask 背后的實現原理也是基于異步消息處理機制的,只是Android 幫我們做了很好的封裝而已。 AsyncTask 允許對用戶界面執行異步操作。它會先阻塞工作線程中的操作,然后在 UI 線程中發布結果,而無需您親自處理線程和處理程序。要使用它,必須**創建 AsyncTask 子類并實現 doInBackground() 回調方法**,該方法將在后臺線程池中運行。要**更新 UI,必須實現 onPostExecute() 以傳遞doInBackground() 返回的結果并在 UI 線程中運行**,這樣,您即可安全更新 UI。稍后,您可以**通過從 UI 線程調用 execute() 來運行任務**。 **AsyncTask 是一個抽象類**,所以如果我們想使用它,就**必須要創建一個子類去繼承它**。在繼承時我們可以為AsyncTask 類指定3個泛型參數,這3個參數的用途如下。 * Params:在執行AsyncTask 時需要傳入的參數,可用于在后臺任務中使用。 * Progress:后臺任務執行時,如果需要在界面上顯示當前的進度,則使用這里指定的泛型作為進度單位。 * Result:當任務執行完畢后,如果需要對結果進行返回,則使用這里指定的泛型作為返回值類型。 目前我們自定義的DownloadTask 還是一個空任務,并不能進行任何實際的操作,我們還需要去重寫AsyncTask 中的幾個方法才能完成對任務的定制。經常需要去重寫的方法有以下4 個。 * onPreExecute() * doInBackground(Params ... ) * onProgressUpdate(Progress ... ) * onPostExecute(Result) AsyncTask 參考文檔: * 可以使用泛型指定參數類型、進度值和任務最終值 * 方法 **doInBackground() 會在工作線程(非UI線程)上自動執行** * **onPreExecute()、onPostExecute() 和 onProgressUpdate() 均在 UI 線程中調用** * doInBackground() 返回的值將發送到 onPostExecute() * 您可以隨時在 doInBackground() 中調用publishProgress(),以在 UI 線程中執行 onProgressUpdate() * 您可以隨時取消任何線程中的任務 #### **Android多線程** 關于Android多線程的知識點補充: 當我們啟動一個App的時候,Android系統會啟動一個Linux Process,該Process包含一個Thread,稱為UI Thread或Main Thread。通常一個應用的所有組件都運行在這一個Process中,當然,你可以通過修改四大組件在Manifest.xml中的代碼塊(`<activity><service><provider><receiver>`)中的**android:process**屬性指定其運行在不同的process中。當一個組件在啟動的時候,如果該process已經存在了,那么該組件就直接通過這個process被啟動起來,并且運行在這個process的UI Thread中。 UI Thread中運行著許多重要的邏輯,如系統事件處理,用戶輸入事件處理,UI繪制,Service,Alarm等 :-: ![](https://upload-images.jianshu.io/upload_images/2839011-23a52dcb6f73550f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/493) 圖8:UI Thread包含的邏輯 我們編寫的代碼則是穿插在這些邏輯中間,比如對用戶觸摸事件的檢測和響應,對用戶輸入的處理,自定義View的繪制等。如果我們插入的代碼比價耗時,如網絡請求或數據庫讀取,就會阻塞UI線程其他邏輯的執行,從而導致界面卡頓。如果卡頓時間超過5秒,系統就會報ANR錯誤。所以,如果要執行耗時的操作,我們需要另起線程執行。 在新線程執行完耗時的邏輯后,往往需要將結果反饋給界面,進行UI更新。Android的UI toolkit(UI 工具包)不是線程安全的,不能在非UI線程進行UI的更新,所有對界面的更新必須在UI線程進行。 Android UI 工具包組件:來自 android.widget 和 android.view 軟件包的組件。 Android提供了四種常用的操作多線程的方式,分別是: 1. Handler+Thread 2. AsyncTask 3. ThreadPoolExecutor 4. IntentService ##### **Handler+Thread** Android主線程包含一個消息隊列(MessageQueue),該消息隊列里面可以存入一系列的Message或Runnable對象。通過一個Handler你可以往這個消息隊列發送Message或者Runnable對象,并且處理這些對象。每次你新創建一個Handle對象,它會綁定于創建它的線程(也就是UI線程)以及該線程的消息隊列,從這時起,這個handler就會開始把Message或Runnable對象傳遞到消息隊列中,并在它們出隊列的時候執行它們。 :-: ![](https://upload-images.jianshu.io/upload_images/2839011-7036df5ffea97ec2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/465) 圖9 :Handler Thread原理圖 Handler可以把一個Message對象或者Runnable對象壓入到消息隊列中,進而在UI線程中獲取Message或者執行Runnable對象,Handler把壓入消息隊列有兩類方式,Post和sendMessage: **Post方式**: Post允許把一個Runnable對象入隊到消息隊列中。它的方法有: ~~~ post(Runnable) postAtTime(Runnable,long) postDelayed(Runnable,long) ~~~ 對于Handler的Post方式來說,它會傳遞一個Runnable對象到消息隊列中,在這個Runnable對象中,重寫run()方法。一般在這個run()方法中寫入需要在UI線程上的操作。 :-: ![](https://upload-images.jianshu.io/upload_images/2839011-b1d72fd4b937a29e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700) 圖10:handler post用法 **sendMessage**: sendMessage允許把一個包含消息數據的Message對象壓入到消息隊列中。它的方法有: ~~~ sendEmptyMessage(int) sendMessage(Message) sendMessageAtTime(Message,long) sendMessageDelayed(Message,long) ~~~ Handler如果使用sendMessage的方式把消息入隊到消息隊列中,需要傳遞一個Message對象,而在Handler中,需要重寫handleMessage()方法,用于獲取工作線程傳遞過來的消息,此方法運行在UI線程上。Message是一個final類,所以不可被繼承。 :-: ![](https://upload-images.jianshu.io/upload_images/2839011-cdfe976cd627891b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700) 圖11:handler定義 :-: ![](https://upload-images.jianshu.io/upload_images/2839011-2dd38fe2116901a0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700) 圖12:handler sendMessage用法 **優缺點** 1. Handler用法簡單明了,可以將多個異步任務更新UI的代碼放在一起,清晰明了 2. 處理單個異步任務代碼略顯多 **適用范圍** 1. 多個異步任務的更新UI ##### **AsyncTask** [AsyncTask](https://www.androidos.net.cn/android/6.0.1_r16/xref/frameworks/base/core/java/android/os/AsyncTask.java)是android提供的輕量級的異步類,可以直接繼承AsyncTask,在類中實現異步操作,并提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更新),最后反饋執行的結果給UI主線程。 AsyncTask通過一個阻塞隊列`BlockingQuery<Runnable>`存儲待執行的任務,利用靜態線程池THREAD_POOL_EXECUTOR提供一定數量的線程,默認128個。在Android 3.0以前,默認采取的是并行任務執行器,3.0以后改成了默認采用串行任務執行器,通過靜態串行任務執行器SERIAL_EXECUTOR控制任務串行執行,循環取出任務交給THREAD_POOL_EXECUTOR中的線程執行,執行完一個,再執行下一個。 ~~~ class DownloadTask extends AsyncTask<Integer, Integer, String>{ // AsyncTask<Params, Progress, Result> //后面尖括號內分別是參數(例子里是線程休息時間),進度(publishProgress用到),返回值類型 @Override protected void onPreExecute() { //第一個執行方法 super.onPreExecute(); } @Override protected String doInBackground(Integer... params) { //第二個執行方法,onPreExecute()執行完后執行 for(int i=0;i<=100;i++){ publishProgress(i); try { Thread.sleep(params[0]); } catch (InterruptedException e) { e.printStackTrace(); } } return "執行完畢"; } @Override protected void onProgressUpdate(Integer... progress) { //這個函數在doInBackground調用publishProgress時觸發,雖然調用時只有一個參數 //但是這里取到的是一個數組,所以要用progesss[0]來取值 //第n個參數就用progress[n]來取值 tv.setText(progress[0]+"%"); super.onProgressUpdate(progress); } @Override protected void onPostExecute(String result) { //doInBackground返回時觸發,換句話說,就是doInBackground執行完后觸發 //這里的result就是上面doInBackground執行后的返回值,所以這里是"執行完畢" setTitle(result); super.onPostExecute(result); } } ~~~ **優缺點** 1. 處理單個異步任務簡單,可以獲取到異步任務的進度 2. 可以通過cancel方法取消還沒執行完的AsyncTask 3. 處理多個異步任務代碼顯得較多 **適用范圍** 1. 單個異步任務的處理 ##### **ThreadPoolExecutor** ThreadPoolExecutor提供了一組線程池,可以管理多個線程并行執行。這樣一方面減少了每個并行任務獨自建立線程的開銷,另一方面可以管理多個并發線程的公共資源,從而提高了多線程的效率。所以ThreadPoolExecutor比較適合一組任務的執行。Executors利用工廠模式對ThreadPoolExecutor進行了封裝,使用起來更加方便。 :-: ![](https://upload-images.jianshu.io/upload_images/2839011-d3869fae4dff8272.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/520) 圖13:ThreadPoolExecutor Executors提供了四種創建ExecutorService的方法,他們的使用場景如下: 1. Executors.newFixedThreadPool() 創建一個定長的線程池,每提交一個任務就創建一個線程,直到達到池的最大長度,這時線程池會保持長度不再變化 2. Executors.newCachedThreadPool() 創建一個可緩存的線程池,如果當前線程池的長度超過了處理的需要時,它可以靈活的回收空閑的線程,當需要增加時, 它可以靈活的添加新的線程,而不會對池的長度作任何限制 3. Executors.newScheduledThreadPool() 創建一個定長的線程池,而且支持定時的以及周期性的任務執行,類似于Timer 4. Executors.newSingleThreadExecutor() 創建一個單線程化的executor,它只創建唯一的worker線程來執行任務 **適用范圍** 1. 批處理任務 ##### **IntentService** [IntentService](https://www.androidos.net.cn/android/6.0.1_r16/xref/frameworks/base/core/java/android/app/IntentService.java)繼承自Service,是一個抽象類,是一個經過包裝的輕量級的Service,用來接收并處理通過Intent傳遞的異步請求。客戶端通過調用startService(Intent)啟動一個IntentService,利用一個work線程依次處理順序過來的請求,處理完成后自動結束Service。 特點 1. 一個可以處理異步任務的簡單Service 它使用工作線程逐一處理所有啟動請求。如果您不要求服務同時處理多個請求,這是最好的選擇。 您只需實onHandleIntent() 方法即可,該方法會接收每個啟動請求的 Intent,使您能夠執行后臺工作。 擴展 IntentService 類(IntentService 類是一個抽象類,所以需要實現它的子類)特點 * 1、不需要開啟線程, * 2、不需要關閉服務,它自己關閉 * 3、單線程下載 由于大多數啟動服務都不必同時處理多個請求(實際上,這種多線程情況可能很危險),因此使用 IntentService 類實現服務也許是最好的選擇。 IntentService 執行以下操作: * 創建默認的工作線程,用于在應用的主線程外執行傳遞給 onStartCommand() 的所有 Intent。 * 創建工作隊列,用于將一個 Intent 逐一傳遞給 onHandleIntent() 實現,這樣您就永遠不必擔心多線程問題。 * 在處理完所有啟動請求后停止服務,因此您永遠不必調用 stopSelf()。 * 提供 onBind() 的默認實現(返回 null)。 * 提供 onStartCommand() 的默認實現,可將 Intent 依次發送到工作隊列和 onHandleIntent() 實現。 * 綜上所述,您只需實現 onHandleIntent() 來完成客戶端提供的工作即可。(不過,您還需要為服務提供小型構造函數。) 示例: ~~~ public class HelloIntentService extends IntentService { /** * A constructor is required, and must call the super IntentService(String) * constructor with a name for the worker thread. */ public HelloIntentService() { super("HelloIntentService"); } /** * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } } } ~~~ 只需要一個構造函數和一個 onHandleIntent() 實現即可;不需要開線程。 如果您決定還重寫其他回調方法(如 onCreate()、onStartCommand() 或 onDestroy()),請確保調用超類實現(return super.onStartCommand(intent,flags,startId);),以便 IntentService 能夠妥善處理工作線程的生命周期。 例如,onStartCommand() 必須返回默認實現-----return super.onStartCommand(intent,flags,startId);(即,如何將 Intent 傳遞給 onHandleIntent()): ~~~ @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent,flags,startId); } ~~~ 除 onHandleIntent() 之外,您無需從中調用超類的唯一方法就是 onBind()(僅當服務允許綁定時,才需要實現該方法)。 IntentService 可用于**執行后臺耗時的任務**,當任務執行后它會自動停止, 同時由于IntentService 是服務的原因,這導致它的優先級比單純的線程要高很多,所以IntentService 比較**適合執行一些高優先級的后臺任務**,因為它**優先級高不容易被系統殺死。** 在實現上, IntentService 封裝了HandlerThread 和Handler,這一點可以從它的onCreate方法中看出來,
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看