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方法,子類實現即可