標籤:pat amp etl extra 工作 self 非同步請求 put 注意事項
一、 定義
IntentService是Android裡面的一個封裝類,繼承自四大組件之一的Service。
二、作用
處理非同步請求,實現多線程
三、 工作流程
注意:若啟動IntentService 多次,那麼每個耗時操作則以隊列的方式在 IntentService的onHandleIntent回調方法中依次執行,執行完自動結束。
四、實現步驟
- 步驟1:定義IntentService的子類:傳入線程名稱、複寫onHandleIntent()方法
- 步驟2:在Manifest.xml中註冊服務
- 步驟3:在Activity中開啟Service服務
五、具體執行個體
- 步驟1:定義IntentService的子類:傳入線程名稱、複寫onHandleIntent()方法
package com.example.carson_ho.demoforintentservice;import android.app.IntentService;import android.content.Intent;import android.util.Log;/** * Created by Carson_Ho on 16/9/28. */public class myIntentService extends IntentService { /*建構函式*/ public myIntentService() { //調用父類的建構函式 //建構函式參數=背景工作執行緒的名字 super("myIntentService"); } /*複寫onHandleIntent()方法*/ //實現耗時任務的操作 @Override protected void onHandleIntent(Intent intent) { //根據Intent的不同進行不同的交易處理 String taskName = intent.getExtras().getString("taskName"); switch (taskName) { case "task1": Log.i("myIntentService", "do task1"); break; case "task2": Log.i("myIntentService", "do task2"); break; default: break; } } @Override public void onCreate() { Log.i("myIntentService", "onCreate"); super.onCreate(); } /*複寫onStartCommand()方法*/ //預設實現將請求的Intent添加到工作隊列裡 @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("myIntentService", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.i("myIntentService", "onDestroy"); super.onDestroy(); }}
<service android:name=".myIntentService"> <intent-filter > <action android:name="cn.scu.finch"/> </intent-filter> </service>
- 步驟3:在Activity中開啟Service服務
package com.example.carson_ho.demoforintentservice;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //同一服務只會開啟一個背景工作執行緒 //在onHandleIntent函數裡依次處理intent請求。 Intent i = new Intent("cn.scu.finch"); Bundle bundle = new Bundle(); bundle.putString("taskName", "task1"); i.putExtras(bundle); startService(i); Intent i2 = new Intent("cn.scu.finch"); Bundle bundle2 = new Bundle(); bundle2.putString("taskName", "task2"); i2.putExtras(bundle2); startService(i2); startService(i); //多次啟動 } }
六、源碼分析
接下來,我們會通過源碼分析解決以下問題:
- IntentService如何單獨開啟一個新的背景工作執行緒;
- IntentService如何通過onStartCommand()傳遞給服務intent被依次插入到工作隊列中
問題1:IntentService如何單獨開啟一個新的背景工作執行緒
// IntentService源碼中的 onCreate() 方法@Overridepublic void onCreate() { super.onCreate(); // HandlerThread繼承自Thread,內部封裝了 Looper //通過執行個體化HandlerThread建立線程並啟動 //所以使用IntentService時不需要額外建立線程 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); //獲得背景工作執行緒的 Looper,並維護自己的工作隊列 mServiceLooper = thread.getLooper(); //將上述獲得Looper與建立的mServiceHandler進行綁定 //建立的Handler是屬於背景工作執行緒的。 mServiceHandler = new ServiceHandler(mServiceLooper);}private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); }//IntentService的handleMessage方法把接收的訊息交給onHandleIntent()處理//onHandleIntent()是一個抽象方法,使用時需要重寫的方法 @Override public void handleMessage(Message msg) { // onHandleIntent 方法在背景工作執行緒中執行,執行完調用 stopSelf() 結束服務。 onHandleIntent((Intent)msg.obj); //onHandleIntent 處理完成後 IntentService會調用 stopSelf() 自動停止。 stopSelf(msg.arg1); }}////onHandleIntent()是一個抽象方法,使用時需要重寫的方法@WorkerThreadprotected abstract void onHandleIntent(Intent intent);
問題2:IntentService如何通過onStartCommand()傳遞給服務intent被依次插入到工作隊列中
public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;}public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId;//把 intent 參數封裝到 message 的 obj 中,然後發送訊息,即添加到訊息佇列裡//這裡的Intent 就是啟動服務時startService(Intent) 裡的 Intent。 msg.obj = intent; mServiceHandler.sendMessage(msg);}//清除訊息佇列中的訊息@Overridepublic void onDestroy() { mServiceLooper.quit();}
因此我們通過複寫方法onHandleIntent(),再在裡面根據Intent的不同進行不同的線程操作就可以了
注意事項 工作任務隊列是順序執行的。
如果一個任務正在IntentService中執行,此時你再發送一個新的工作要求,這個新的任務會一直等待直到前面一個任務執行完畢才開始執行
原因:
- 由於onCreate() 方法只會調用一次,所以只會建立一個背景工作執行緒;
- 當多次調用 startService(Intent) 時(onStartCommand也會調用多次)其實並不會建立新的背景工作執行緒,只是把訊息加入訊息佇列中等待執行,所以,多次啟動 IntentService 會按順序執行事件
- 如果服務停止,會清除訊息佇列中的訊息,後續的事件得不到執行。
七、使用情境
八、對比8.1 IntentService與Service的區別
Service:依賴於應用程式的主線程(不是獨立的進程 or 線程)
不建議在Service中編寫耗時的邏輯和操作,否則會引起ANR;
IntentService:建立一個背景工作執行緒來處理多線程任務
8.2 IntentService與其他線程的區別
對於後台線程,若進程中沒有活動的四大組件,則該線程的優先順序非常低,容易被系統殺死,無法保證任務的執行
九、參考文章
https://github.com/LRH1993/android_interview/blob/master/android/basis/IntentService.md
Android面試收集錄9 IntentService詳解