簡介
- 在Android應(yīng)用的程序中菊值,普通的Service中的代碼是運行在主線程中的壳猜,如果想要在Service中做些耗時的操作缰盏,就很容易出現(xiàn)ANR的現(xiàn)象(大概是20秒)祠锣,那么我們經(jīng)常的做法就是,在onStartCommon方法中開啟一個子線程然后內(nèi)部執(zhí)行耗時的操作泵三,在執(zhí)行完畢后如果需要自動停止服務(wù)需要在子線程的run方法中調(diào)用stopSelf()來停止服務(wù)耕捞。
- 雖說在Service中執(zhí)行耗時的代碼可以很容易的實現(xiàn)衔掸,但是Android提供的IntentService類可以很方便的解決了自己開啟線程和手動停止服務(wù)的問題。接下來看看IntentService的使用步驟砸脊。
使用步驟
- IntentService是一個抽象類內(nèi)部有一個抽象的方法 handleIntent(),繼承至Service類.所以使用它需要繼承它實現(xiàn)抽象方法具篇。
public class MyIntentService extends IntentService { private static final String TAG = "MyIntentService"; public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(Intent intent) { //在這里通過intent攜帶的數(shù)據(jù)纬霞,開進行任務(wù)的操作凌埂。 Log.d(TAG, "onHandleIntent: " + Thread.currentThread().getName()); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: "); } }
- 然后調(diào)用StartService()啟動異步后臺服務(wù)類 IntentService。
startService.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, MyIntentService.class); startService(intent); } });
源碼分析
- 服務(wù)啟動的過程中诗芜,會去執(zhí)行服務(wù)的生命周期方法瞳抓,在開啟服務(wù)的時候,有兩種方式伏恐,分別為startService和bindService
- startService方式啟動孩哑,生命周期方法執(zhí)行的順序是 onCreate(),onStartCommand() onStart() onDestroy(),按照生命周期執(zhí)行順序我們查看IntentService的源碼
// onCreate方法的分析
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
//創(chuàng)建了一個Looper對象 & MessageQueue對象 調(diào)用了Looper.loop方法
thread.start();
// 獲取到HandlerThread中創(chuàng)建好的Looper對象翠桦。
mServiceLooper = thread.getLooper();
//ServiceHandler extends Handler横蜒,綁定了HandlerThread中的Looper對象 ;那個線程調(diào)用了Looper中的loop方法销凑,Handler的dispatchMessage方法就運行在那個線程中丛晌。
mServiceHandler = new ServiceHandler(mServiceLooper);
}
//onStartCommand()方法分析
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
// 調(diào)用了onStart方法
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
//onStart方法
public void onStart(@Nullable Intent intent, int startId) {
//在這里構(gòu)造了一個消息對象
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
//將intent 包裝到了Message的obj中,
msg.obj = intent;
//然后調(diào)用sendMessage()將消息插入到隊列中斗幼。
//最終消息被取出然后被分發(fā)澎蛛,最后調(diào)用了handleMessage()來處理這個消息
mServiceHandler.sendMessage(msg);
}
//ServiceHandler handleMessage方法的分析
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//SeriviceHandler 的handleMessage()方法中 將接受到的消息交給onHandleIntent來處理,onHandleIntent方法就是我們實現(xiàn)的方法蜕窿,獲取到Intent谋逻,處理任務(wù)。
onHandleIntent((Intent) msg.obj);
//執(zhí)行完 結(jié)束服務(wù)
stopSelf(msg.arg1);
}
}
// onDestroy()方法的處理
@Override
public void onDestroy() {
//將消息隊列中的所有消息給移除桐经,包括處理中的和未處理的
mServiceLooper.quit();
}
總結(jié)說來就是毁兆,開啟服務(wù)執(zhí)行onCreate()方法,方法中創(chuàng)建好了一個子線程(HandlerThread)阴挣,(子線程中創(chuàng)建好了一個Looper對象同時創(chuàng)建好了一個MessagqQueue消息隊列气堕,然后開啟輪詢消息隊列。)屯吊,內(nèi)部創(chuàng)建好的Handler與子線程中的Looper對象綁定送巡。onCreate只有在服務(wù)第一次創(chuàng)建的時候才會調(diào)用,之后每次調(diào)用都只會執(zhí)行onStartCommand方法盒卸,在此方法中我們構(gòu)建好了一個Message對象骗爆,并且將傳遞進來的Intent封裝在Mesage,一起發(fā)送到消息隊列中蔽介。經(jīng)過輪詢將消息分發(fā)到Handler的handleMessage中處理摘投,此時獲取到Message中攜帶的Intent傳遞給我們實現(xiàn)好的handleIntent方法中進行任務(wù)的處理煮寡,處理完畢自動調(diào)用StopSlef來結(jié)束服務(wù)。在onDestroy方法會把所有消息都給退出犀呼。
- 上文中我們分析了startService方法啟動的服務(wù)幸撕,那bindService方式啟動服務(wù)的分析如下(綁定服務(wù),建立長期通信)外臂,bindService啟動會執(zhí)行 onCreate -> onBind -> onUnBind -> onDestroy方法坐儿。
//onCreate方法上文中已經(jīng)分析
//onBind()
public IBinder onBind(Intent intent) {
//直接返回null了。那么不對會Mesage對象和發(fā)送消息到隊列中宋光,
//然后回調(diào)handleIntent方法了貌矿。
return null;
}
所以bindService方式啟動服務(wù),不會進行多線程的操作罪佳。
問題記錄
簡單描述一下IntentService
- IntentService是一個特殊的Service類逛漫,是實現(xiàn)了多線程處理異步請求的一個服務(wù)類,在handleIntent方法中進行耗時的操作赘艳,如果有多個耗時的操作任務(wù)酌毡,會按照順序去一個一個的執(zhí)行,執(zhí)行完一個關(guān)閉一個蕾管。
在源碼handleMessage方法中為什么執(zhí)行完handleIntent方法會去調(diào)用帶參數(shù)的stopSelf()
- 因為stopSelf()的執(zhí)行會立刻將服務(wù)停止掉枷踏,而帶參數(shù)的stopSelf(int startId)會在所有任務(wù)執(zhí)行完畢后將服務(wù)給停止。通常情況下調(diào)用stopSelf(int satrtId)方法不會立刻去執(zhí)行停止服務(wù)的操作娇掏,會去判斷最近執(zhí)行任務(wù)的次數(shù)是否和startId相等呕寝,如果相等就立刻執(zhí)行停止服務(wù)的操作。