IntentService使用以及源碼分析
一 概述
我們知道,在Android開發中,遇到耗時的任務操作時,都是放到子線程去做,或者放到Service中去做,在Service中開一個子線程來執行耗時操作。
那麽,在Service裏面我們需要自己管理Service的生命周期,何時開啟何時關閉,還是很麻煩的,還好Android給我們提供了一個這樣的類,叫做IntentService
那麽IntentService是做什麽用的呢?
IntentService: 是繼承於Service的一個類,用來處理異步請求。可以直接通過startService(Intent intent)來提交請求,Service的創建,關閉,開子線程等工作,IntentService內部都幫我們封裝好了,我們只需要發請求處理請求就行了。
如此簡單
我們先來看一下IntentService的用法
二 IntentService用法
假如我們現在有一個下載文件的需求,我們需要開啟一個Service並在裏面開啟一個子線程中去下載文件。
1 先繼承IntentService實現一個類,我們叫做 DownloadService如下
public class DownloadService extends IntentService { //重寫無參的構造方法 public DownloadService(){ super("DownloadService"); } @Override protected void onHandleIntent(Intent intent) { String url = intent.getStringExtra("url"); downloadFile(url); } //下載文件 private void downloadFile(String url){ try { Log.e("DownloadService","當前線程名:" + Thread.currentThread().getName()); Log.e("DownloadService","文件開始下載... url="+url); //模擬下載文件操作 Thread.sleep(3000); Log.e("DownloadService","文件下載完成..."); } catch (InterruptedException e) { e.printStackTrace(); } } }
繼承IntentService類,實現onHandleIntent(Intent intent)
方法
註意,不要忘了DownloadService需要在清單文件中註冊
2 我們在界面上的按鈕的點擊事件中,來下載一個文件,如下
findViewById(R.id.tv_hello).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("DownloadService","當前線程名:"+Thread.currentThread().getName()); //像平時啟動service方式一樣,沒有任何區別 Intent intent = new Intent(MainActivity.this,DownloadService.class); intent.putExtra("url","http://xx/test.apk"); startService(intent); } });
點擊按鈕,輸出
E/DownloadService: 當前線程名:main
E/DownloadService: 當前線程名:IntentService[DownloadService]
E/DownloadService: 文件開始下載... url=http://xx/test.apk
E/DownloadService: 文件下載完成...
通過輸出日誌,可以看到,開啟任務是在主線程中,而執行下載文件的耗時任務,是在子線程中,使用的時候,只需要startService(Intent intent),並通過intent把所需要的數據帶過去就行了。是不是很簡單。
下面來分析IntentService是如何做到的?
## 三 IntentService源碼分析
1 看下IntentService的類定義
```
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
......
}
```
可以看到,IntentService有幾個需要註意的地
IntentService是一個Service也是一個抽象類,子類只需要實現
void onHandleIntent(@Nullable Intent intent)
並在裏面添加自己的業務即可IntentService類中有一個
Looper mServiceLooper
以及一個ServiceHandler mServiceHandler
,ServiceHandler
繼承Handler
,並在handleMessage()
中調用了外部類的onHandleIntent
方法在
ServiceHandler
的handleMessage()
方法中,執行完onHandleIntent((Intent)msg.obj)
,調用了stopSelf(msg.arg1)
來關閉這個Service
所以IntentService
不用去管怎麽創建的,怎麽關閉的,怎麽開啟線程的,我們只需要繼承IntentService
,實現onHandleIntent()
方法並在裏面執行我們的邏輯就行了,執行完任務之後,自動會把Service
關閉。這一切都是IntentService
幫我們封裝好了的。
2 startService之後,會走Service的生命周期方法,onCreate()源碼如下
@Override
public void onCreate() {
super.onCreate();
//還記得上一篇講的HandlerThread源碼分析嗎
//創建一個HandlerThread對象,並調用start()方法
//使之成為一個looper線程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//拿到上面創建的looper線程對應的looper
//並傳給ServiceHandler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
很明顯,在onCreate中創建了一個線程而且是一個looper線程,又創建了一個Handler對象,並把這個線程的looper傳給了這個Handler,那麽這個Handler發送的任務消息都會由這個ServiceHandler處理了
再看看 onStart()方法和onStartCommand()方法,如下
onStart()方法
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
onStartCommand()方法
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
startService方法啟動的時候,第一次會調用onCreate() -> onStart() -> onStartCommand()方法
而且之後再次調用startService方法啟動的時候,不會再調用onCreate()方法了,而是會調用onStandCommand()方法
而在IntentService中,onStartCommand()方法中又會調用onStart()方法,所以,我們只需要分析onStart()方法即可
onStart()方法源碼
@Override
public void onStart(@Nullable Intent intent, int startId){
//使用mServiceHandler獲取一個消息
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
//發送這個消息
mServiceHandler.sendMessage(msg);
}
通過上面可知,我們調用startService方法啟動service的時候,會調用onStart()方法,在這個方法裏面,把intent和startId賦值給了 msg ,並發送消息。這時候會調用Handler的handleMessag()方法,ServiceHandler的源碼如下:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
......
}
可以看到ServiceHandler是IntentService的內部類,而且在handleMessage中會調用IntentService的 onHandleIntent()方法,並把 intent 參數也傳過去。
我們來看下 onHandleIntent()方法
protected abstract void onHandleIntent(@Nullable Intent intent);
是一個抽象方法,這時候就需要子類去實現這個方法並在裏面做耗時的操作即可。
經過上面的分析可知,IntentService使用也非常方便,原理就是利用HandlerThread開啟了一個looper線程,並在onStart中把intent通過msg發送出去,並在handleMessage中又調用了onHandleIntent方法,子類實現即可
IntentService使用以及源碼分析