概述
大家知道,普通Service服務是運行在UI線程上的,這就意味着如果我們需要通過Service執行一些耗時的操作,我們必須要通過創建一個工作線程來完成,否則應用可能會出現ANR異常。
IntentService就是爲了解決這個問題而出現的。IntentService是Service的一個子類,該類的作用就是可以讓服務在工作線程中執行任務,而不需要自行創建工作線程。
IntentService的主要作用(優點):
1. 在IntentService中會默認創建工作線程用於執行傳遞的Intent,這樣在執行耗時操作時不需要手動去創建線程了
2. 在IntentService中創建工作隊列,用於將 Intent 逐一傳遞給 onHandleIntent() 實現,這樣就永遠不必擔心多線程問題。
3. 在處理完所有啓動請求後停止服務,因此您永遠不必調用 stopSelf()。
4. IntentService的onBind方法默認返回null
IntentService源碼分析
在IntentService中,主要使用到了HandlerThread。HandlerThread是Thread的一個子類,在該類中可以使用Handler。其實HandlerThread的實現原理非常簡單,就是在run方法中通過Looper.prepare()來創建消息隊列,然後通過Looper.loop()方法開啓消息循環,整個實現流程如同ActivityThread.main()方法中MainLooper的初始化過程。
具體關於HandlerThread的介紹,請看 Android HandlerThread源碼分析。
IntentServcie源碼分析
public abstract class IntentService extends Service {
/**
* 1、在IntentServcie被首次創建時,會執行onCreate方法
*/
@Override
public void onCreate() {
super.onCreate();
// 1、創建一個HandlerThread,用於接收消息
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
// 2、獲取上面HandlerThread的實例的looper
mServiceLooper = thread.getLooper();
// 3、通過HandlerThread的looper,創建一個handler對象mServiceHandler,這樣通過mServiceHandler發送的對象都會在HandlerThread中被處理
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/**
* 2、每次啓動IntentServcie, onStartCommand方法會被調用,該方法內部主要調用onStart方法
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
/**
* 3、在onStrat方法中主要是通過mServiceHandler發送了一條消息。
* <p>
* 在mServiceHandler發送的消息中,intent對象會作爲發送消息的參數(這裏的intent和通過startServcie方法傳遞的intent是同一個對象)
* <p>
* 同時,消息中會被攜帶一個startId的參數,該參數主要用於判斷服務是否結束
*/
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* 4、ServiceHandler,該handler對象是通過HandlerThread的looper創建的,所以通過ServiceHandler
* 發送的消息都會被髮送到HandlerThread中執行,由於HandlerThread是一個Thread類,這樣就實現了在IntentService
* 無需創建一個Thread來執行後臺耗時任務。
* <p>
* 同時,由於ServiceHandler內部的消息隊列是通過looper維護的,這樣就保證了消息隊列是順序執行的,所以IntentService也是
* 順序執行任務的。
*/
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
/*
* 1、抽象方法,需要在子類中實現具體後臺任務的實現
*/
onHandleIntent((Intent) msg.obj);
/*
* 2、在任務執行完成,自動停止服務。
*
* msg.arg1 就是在startId,這是爲每一消息生成的唯一標識。每通過IntentService處理一個請求時,
* 都會有一個消息被放入到消息隊列中,只有當最後一個消息執行完成即msg.arg1等於最後一個放入到消息隊列的startId,
* 服務纔會被停止,否者IntentService不會被停止
*
* 這樣做的好處就是:保證消息隊列中的所有消息都被處理,服務纔會被停止。
*
*/
stopSelf(msg.arg1);
}
}
/**
* 5、抽象方法,該方法需要在IntentService的子類中實現,也是IntentService中唯一一個需要實現的方法
*
* @param intent
*/
protected abstract void onHandleIntent(Intent intent);
@Override
public void onDestroy() {
// 退出消息隊列循環
mServiceLooper.quit();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
// 默認返回null
return null;
}
}
IntentService的簡單使用
這裏通過IntentService模擬一個簡單的下載任務。
public class IntentServcieActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_servcie);
Button button = findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
private int urlid;
@Override
public void onClick(View v) {
Intent intent = new Intent(IntentServcieActivity.this, DownloadService.class);
intent.putExtra(DownloadService.DOWN_URL, "url" + ++urlid);
startService(intent);
}
});
}
}
/**
* 通過IntentService完成下載任務
*/
public class DownloadService extends IntentService {
public static final String DOWN_URL = "down_url";
public DownloadService() {
super("DownloadService");
}
@Override
protected void onHandleIntent(Intent intent) {
String url = intent.getStringExtra(DOWN_URL);
downlaod(url);
}
/**
* 模擬下載任務
*/
private void downlaod(String url) {
Log.e("zhangke", "url = " + url + " 正在下載中...");
SystemClock.sleep(3000);
Log.e("zhangke", "url = " + url + " 下載完成");
}
}