前言
Service作為Android的四大組件之一萄涯,實現(xiàn)了在后臺執(zhí)行不需要界面的任務,例如音樂的播放等唆鸡,若要實現(xiàn)一個在后臺執(zhí)行的耗時任務呢涝影?例如離線下載。于是争占,Android 實現(xiàn)了 IntentService 燃逻,通過開啟一個子線程在后臺執(zhí)行耗時任務序目。
1. 使用步驟
1)新建IntentService子類MyIntentService
2)重寫 onHandleIntent()
方法,根據(jù)傳入的不同Intent處理不同的任務
3)在 AndroidManifest.xml
中注冊服務MyIntentService
4)需要發(fā)起任務請求的地方唆樊,新建 Intent
對象宛琅,使用 Bundle
保存?zhèn)魅氲臄?shù)據(jù)
5)調(diào)用 Activity
的 startService(intent)
發(fā)起一次任務請求
MyIntentService.java
//step1: 新建IntentService子類MyIntentService
public class MyIntentService extends IntentService {
private String taskName;
//step2: 調(diào)用父類構(gòu)造方法,傳入線程名字
public MyIntentService() {
super("myIntentService");
}
@Override
public void onCreate() {
super.onCreate();
Log.i("myIntentService----", "onCreate");
}
//默認實現(xiàn)逗旁,將傳入的Intent請求依次加入到消息隊列中
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.i("myIntentService----", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("myIntentService----", "onDestroy");
}
}
AndroidManifest.xml
<service
android:name=".MyIntentService"
tools:ignore="ExportedService"/>
發(fā)起任務請求的方法:
//在需要發(fā)起任務請求的地方調(diào)用此方法
private void startIntentService() {
//step5: 新建Intent傳入任務處理請求嘿辟,指向MyIntentService
Intent task1 = new Intent(MainActivity.this, MyIntentService.class);
Bundle bundle1 = new Bundle();
bundle1.putString("taskName", "task1");
task1.putExtras(bundle1);
Intent task2 = new Intent(MainActivity.this, MyIntentService.class);
Bundle bundle2 = new Bundle();
bundle2.putString("taskName", "task2");
task2.putExtras(bundle2);
//step6: 啟動服務,發(fā)起一次任務請求 (多次調(diào)用startService(intent) 則發(fā)起多次請求)
startService(task1);
startService(task2);
//再次發(fā)起task1的任務請求
startService(task1);
}
- bug記錄
在AndoridManifest.xml文件中注冊MyIntentService時片效,為Service添加了屬性name红伦,并在代碼中用包名的方式調(diào)用報錯:
Service Intent must be explicit: Intent
原因:Android 5.0(Lollipop) 之后規(guī)定不能以包名的方式定義Service的Intent,而應用顯示聲明new Intent(xxxActivity.this, xxxService.class);
2. 源碼分析
1)IntentService的初始化
//step2: 調(diào)用父類構(gòu)造方法淀衣,傳入線程名字
public MyIntentService() {
super("myIntentService");
}
//調(diào)用了此構(gòu)造方法昙读,賦值線程名稱mName
public IntentService(String name) {
super();
mName = name;
}
//IntentService的onCreate()中
@Override
public void onCreate() {
super.onCreate();
//下面即是開啟一個HandlerThread線程的常用步驟,詳細可參考之前文章中有關HandlerThread的解析
//創(chuàng)建一個新線程HandlerThread對象膨桥,傳入線程名稱mName
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
//啟動線程
thread.start();
//獲取HandlerThread自動創(chuàng)建的Looper
mServiceLooper = thread.getLooper();
//關聯(lián)HandlerThread和IntentService的Handler對象
mServiceHandler = new ServiceHandler(mServiceLooper);
}
2)onHandleIntent(Intent intent)
//step3: 重寫onHandleIntent蛮浑,判斷Intent類型,依次處理不同的任務
@Override
protected void onHandleIntent(Intent intent) {
...
}
//IntentService中只嚣,創(chuàng)建ServiceHandler類沮稚,繼承自Hanlder
private final class ServiceHandler extends Handler {
//構(gòu)造方法,傳入ServiceHandler所在線程的Looper對象
public ServiceHandler(Looper looper) {
super(looper);
}
//復寫handleMessage册舞,處理任務請求
@Override
public void handleMessage(Message msg) {
//進入子類MyIntentService中重寫的構(gòu)造方法onHandleIntent(intent)蕴掏,這個方法的執(zhí)行是在工作線程中
onHandleIntent((Intent)msg.obj);
//調(diào)用Service的stopSelf() 自動停止開啟的IntentService服務,標記為startId
stopSelf(msg.arg1);
}
}
//子類必須實現(xiàn)的構(gòu)造方法调鲸,工作線程執(zhí)行盛杰,根據(jù)Intent
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
3)onStartCommand(intent, flags, startId)
//將傳入的Intent請求依次加入到消息隊列中
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
//IntentService中onStartCommand
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
//調(diào)用onStart(),傳入發(fā)起的任務請求Intent和該次請求的id值startId
onStart(intent, startId);//——→跳轉(zhuǎn)至onStart()方法
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
//onStart()方法
@Override
public void onStart(@Nullable Intent intent, int startId) {
//新建Message對象藐石,存儲intent和startId
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
//ServiceHandler發(fā)送這條消息Message到消息隊列MessageQueue中即供,等待對應的Handler處理消息任務
mServiceHandler.sendMessage(msg);
}
4)onDestroy()
@Override
public void onDestroy() {
//IntentService結(jié)束即MessageQueue內(nèi)部的Message處理完成時,
//自動退出當前線程所持有的Looper于微,Looper自動退出所持有的MessageQueue
mServiceLooper.quit();
}
5)onBind(intent)
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
//返回為空
}
啟動IntentService時募狂,若采用bindService()方式啟動,IntentService的生命周期為:
onCrtate() → onBind() → onUnBind() → onDestroy()
若采用startService()方式啟動角雷,IntentService的生命周期為:
onCrtate() → onStartCommand() → onDestroy()
從生命周期來看,bindService()不會執(zhí)行onStartCommand()性穿,而IntentService在onStartCommand()方法中實現(xiàn)消息的創(chuàng)建和發(fā)送入隊操作勺三,所以IntentService只能通過startService()的方式啟動才能實現(xiàn)HandlerThread線程發(fā)送消息并在后臺Service中執(zhí)行耗時任務。
3. 應用場景
線程任務需要 按序
且在 后臺執(zhí)行
需曾,所有任務都在同一個Thread的Looper中執(zhí)行
離線下載
思考
-
為什么IntentService是
Service + HandlerThread + Handler
的結(jié)合吗坚?
1)IntentService 繼承自 Service
祈远;
2)在 IntentService 的 onCreate()
方法中,創(chuàng)建 HandlerThread
對象商源,開啟子線程執(zhí)行耗時任務车份;
3)創(chuàng)建內(nèi)部類 ServiceHandler
繼承自 Handler
,實現(xiàn)消息的發(fā)送和處理牡彻。
-
為什么IntentService會在執(zhí)行完所有任務請求后自動停止Service?
內(nèi)部類ServiceHandler的handleMessage(msg)方法中扫沼,調(diào)用了父類Service方法stopSelf(),停止了IntentService庄吼。