1. 程式人生 > >Android IntentService詳解

Android IntentService詳解

轉載請註明出處:http://blog.csdn.net/vnanyesheshou/article/details/75125909
最近正在加深基礎,看到個IntentService類,以前從來沒有遇見過,更不知其用來幹嘛的,所以就整理了一個demo,看看這個怎麼使用。
我們經常用到Service,並且在Service開啟執行緒處理耗時操作,Android封裝了一個IntentService類,該類已經幫我們建立好了執行緒供我們使用。

1 簡介

IntentService概括

IntentService is a base class for Service that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
This “work queue processor” pattern is commonly used to offload tasks from an application’s main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
All requests are handled on a single worker thread – they may take as long as necessary (and will not block the application’s main loop), but only one request will be processed at a time.

IntentService是Service的子類,根據需要處理非同步請求(以intent表示)。客戶端通過呼叫startService(Intent) 傳送請求,該Service根據需要啟動,使用工作執行緒處理依次每個Intent,並在停止工作時停止自身。
這種“工作佇列處理器”模式通常用於從應用程式的主執行緒中解除安裝任務。 IntentService類的存在是為了簡化這種模式。 要使用它,擴充套件IntentService並實現onHandleIntent(Intent)。 IntentService將收到Intents,啟動一個工作執行緒,並根據需要停止該服務。
所有請求都在單個工作執行緒處理 - 它們可能需要很長的時間(並且不會阻止應用程式的主迴圈),但是一次只會處理一個請求。

2 程式碼

在IntentService中處理下載請求(模擬),並將進度更新到Ui。
MyIntentService.java程式碼如下:

public class MyIntentService extends IntentService {
    private final static String TAG = "MyIntentService";

    public static final String ACTION_DOWN_IMG = "down.image";
    public static final String ACTION_DOWN_VID = "down.vid"
; public static final String ACTION_DOWN_PROGRESS = "com.zpengyong.down.progress"; public static final String ACTION_SERVICE_STATE = "com.zpengyong.service.state"; public static final String PROGRESS = "progress"; public static final String SERVICE_STATE = "service_state"; //構造方法 一定要實現此方法否則Service執行出錯。 public MyIntentService() { super("MyIntentService"); } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate"); sendServiceState("onCreate"); } @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); Log.i(TAG, ""); } @Override protected void onHandleIntent(Intent intent) { Log.i(TAG, "onHandleIntent thread:"+Thread.currentThread()); String action = intent.getAction(); if(action.equals(ACTION_DOWN_IMG)){ for(int i = 0; i < 100; i++){ try{ //模擬耗時操作 Thread.sleep(50); }catch (Exception e) { } sendProgress(i); } }else if(action.equals(ACTION_DOWN_VID)){ for(int i = 0; i < 100; i++){ try{ //模擬耗時操作 Thread.sleep(70); }catch (Exception e) { } sendProgress(i); } } Log.i(TAG, "onHandleIntent end"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy"); sendServiceState("onDestroy"); } //傳送Service的狀態 private void sendServiceState(String state){ Intent intent = new Intent(); intent.setAction(ACTION_SERVICE_STATE); intent.putExtra(SERVICE_STATE, state); sendBroadcast(intent); } //傳送進度 private void sendProgress(int progress){ Intent intent = new Intent(); intent.setAction(ACTION_DOWN_PROGRESS); intent.putExtra(PROGRESS, progress); sendBroadcast(intent); } }

使用IntentService的方法:

  1. 繼承IntentService。
  2. 實現不帶引數的構造方法,並且呼叫父類IntentService的構造方法。
  3. 實現onHandleIntent方法。

在onHandleIntent方法中可以根據intent來區分任務,這裡有兩個任務,一個是下載圖片、一個是下載視訊(模擬耗時操作)。
執行效果
1 只點擊“啟動任務一”。
這裡寫圖片描述
列印:

07-15 03:07:24.589: I/MyIntentService(3186): onCreate
07-15 03:07:24.593: I/MyIntentService(3186): onHandleIntent thread:Thread[IntentService[MyIntentService],5,main]
07-15 03:07:30.918: I/MyIntentService(3186): onHandleIntent end
07-15 03:07:31.017: I/MyIntentService(3186): onDestroy

IntentService啟動後再onHandleIntent方法中執行任務(該方法工作在子執行緒中),任務執行完後,IntentService銷燬。

2 點選“啟動任務一”,任務未完成時點選“停止Service”。
這裡寫圖片描述
log

07-15 03:08:08.477: I/MyIntentService(3186): onCreate
07-15 03:08:08.478: I/MyIntentService(3186): onHandleIntent thread:Thread[IntentService[MyIntentService],5,main]
07-15 03:08:12.203: I/MyIntentService(3186): onDestroy
07-15 03:08:14.253: I/MyIntentService(3186): onHandleIntent end

IntentService中執行緒執行任務時,stopService會讓IntentService銷燬,但是任務繼續執行,直到執行完成執行緒退出。

3 點選“啟動任務一”,任務完成後點選“啟動任務二”。
這裡寫圖片描述
log資訊:

07-15 03:11:42.366: I/MyIntentService(3186): onCreate
07-15 03:11:42.367: I/MyIntentService(3186): onHandleIntent thread:Thread[IntentService[MyIntentService],5,main]
07-15 03:11:48.285: I/MyIntentService(3186): onHandleIntent end
07-15 03:11:48.289: I/MyIntentService(3186): onDestroy
07-15 03:11:50.174: I/MyIntentService(3186): onCreate
07-15 03:11:50.205: I/MyIntentService(3186): onHandleIntent thread:Thread[IntentService[MyIntentService],5,main]
07-15 03:11:58.446: I/MyIntentService(3186): onHandleIntent end
07-15 03:11:58.510: I/MyIntentService(3186): onDestroy

由上可知,任務執行完成後,執行緒退出迴圈,Service銷燬。重新開啟任務則重新建立Service,執行任務。

4 點選“啟動任務一”,任務完成前點選“啟動任務二”。
這裡寫圖片描述
log資訊

07-15 03:16:46.998: I/MyIntentService(3186): onCreate
07-15 03:16:46.998: I/MyIntentService(3186): onHandleIntent thread:Thread[IntentService[MyIntentService],5,main]
07-15 03:16:52.980: I/MyIntentService(3186): onHandleIntent end
07-15 03:16:52.980: I/MyIntentService(3186): onHandleIntent thread:Thread[IntentService[MyIntentService],5,main]
07-15 03:17:01.048: I/MyIntentService(3186): onHandleIntent end
07-15 03:17:01.053: I/MyIntentService(3186): onDestroy

正常startService啟動兩個任務,第一個未完成前,將第二個任務放到佇列中,等待第一個完成後執行第二個任務,第二個任務完成後,Service自動銷燬。

5 點選“啟動任務一”,任務完成前點選“停止Service”,然後再點選“啟動任務二”。
這裡寫圖片描述
log資訊
這裡寫圖片描述
第一個任務尚未結束時stopservice,IntentService銷燬,其執行緒繼續執行(tid 3691)。此時重新startService會開啟IntentService,其會重新建立一個執行緒執行任務(tid 3692)。兩個任務在兩個執行緒中執行,所以其執行完的先後順序不確定。

3 IntentService原始碼解析

路徑:frameworks/base/core/java/android/app/IntentService.java
先看下IntentService的構造方法和onCreate()。

public abstract class IntentService extends Service {
    //Creates an IntentService.  Invoked by your subclass's constructor.
    public IntentService(String name) {
        super();
            mName = name;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    。。。。
}

IntentService 是繼承Service的一個抽象類,所以需要繼承IntentService 並必須實現其抽象方法onHandleIntent。
繼承IntentService需要實現一個空的構造器,並且呼叫IntentService的構造器。
在onCreate()方法中建立了一個HandlerThread,並允許該執行緒。HandlerThread 不太懂的可以參考我的上一篇文章Android HandlerThread詳解
獲取子執行緒中的Looper例項,然後建立與子執行緒繫結的Handler物件。

接著看IntentService的onStart()。

public void onStart(Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
}

在onStart方法中,建立Message物件,並將“訊息”通過mServiceHandler傳送到子執行緒中的訊息佇列中。
我們知道這些訊息處理還是會分發到Handler中。接著看mServiceHandler

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);
        }
}

訊息會在handlerMessage中處理,該方法中呼叫了onHandleIntent,所以我們需要實現onHandleIntent,在該方法中做我們要做的任務。而訊息處理完成後,呼叫stopSelf將自身Service銷燬。這裡可能會有疑問,既然一個任務執行完成後就會執行stopSelf,那多個任務是怎麼處理的呢?這裡stopSelf(msg.arg1),會先看佇列中是否有訊息待處理,如果有則繼續處理後面的訊息,沒有才會將Service銷燬。
接著看IntentService的onDestroy方法

@Override
public void onDestroy() {
    mServiceLooper.quit();
}

在IntentService的onDestroy方法中會呼叫looper的quit方法,將子執行緒的訊息迴圈停止,等待任務完成後結束子執行緒。

4 總結

IntentService是一個比較便捷的類,省了我們在建立Thread,但是並不能適合所有的情況,它會建立一個執行緒,多個任務按順序執行,並且執行過程中不能夠取消該任務。所以還是需要根據情況進行使用。

歡迎大家指正、交流。