IntentService源碼詳解

來源:互聯網
上載者:User

標籤:android   des   style   blog   http   java   

IntentService可以做什麼:

如果你有一個任務,分成n個子任務,需要它們按照順序完成。如果需要放到一個服務中完成,那麼IntentService就會使最好的選擇。


IntentService是什麼:

IntentService是一個Service(看起來像廢話,但是我第一眼看到這個名字,首先注意的是Intent啊。),所以如果自訂一個IntentService的話,一定要在AndroidManifest.xml裡面聲明。

從上面的“可以做什麼”我們大概可以猜測一下IntentService要有什麼特性。

首先要明確的是,如果在Activity中啟動一個Service,那麼這個Service是在主線程中的。所以在IntentService中需要一個背景工作執行緒來完成Intent請求。從IntentService的定義可以印證該猜測:

IntentService is a base class for Services 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.
IntentService用來按要求處理非同步請求(以Intent的方式發送的)。用戶端通過調用startService(Intent)發送請求,服務會按照要求啟動,用自己的背景工作執行緒(區別於UI主線程)處理每個Intent(請求),當完成所有的請求之後,自動關閉。


IntentService源碼解析:

乾貨來了!IntentService程式碼封裝含了一個背景工作執行緒Thread、背景工作執行緒的Looper、背景工作執行緒的Handler。背景工作執行緒用來幹活的,Looper用來讓線程運轉起來的,Handler負責向線程傳送工作內容的。IntentService的源碼簡潔透徹的體現了這一個機制。光是看看這個機制就值了。源碼如下:

路徑:alps\frameworks\base\core\java\android\app\IntentService.java 

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) {
            //自訂的IntentService子類主要就是實現onHandleIntent這個函數了。注意執行完這個之後就
            //stopSelf了,傳入的參數是startId。            onHandleIntent((Intent)msg.obj);            stopSelf(msg.arg1);        }    }    /**     * Creates an IntentService.  Invoked by your subclass's constructor.     *     * @param name Used to name the worker thread, important only for debugging.     */    public IntentService(String name) {        super();        mName = name;    }    /**     * Sets intent redelivery preferences.  Usually called from the constructor     * with your preferred semantics.     *     * <p>If enabled is true,     * {@link #onStartCommand(Intent, int, int)} will return     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before     * {@link #onHandleIntent(Intent)} returns, the process will be restarted     * and the intent redelivered.  If multiple Intents have been sent, only     * the most recent one is guaranteed to be redelivered.     *     * <p>If enabled is false (the default),     * {@link #onStartCommand(Intent, int, int)} will return     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent     * dies along with it.     */    public void setIntentRedelivery(boolean enabled) {        mRedelivery = enabled;    }    @Override    public void onCreate() {        // TODO: It would be nice to have an option to hold a partial wakelock        // during processing, and to have a static startService(Context, Intent)        // method that would launch the service & hand off a wakelock.        super.onCreate();
        //好好看看下面這個代碼,啟動了一個背景工作執行緒,擷取線程的Looper,然後用這個Looper初始化Handler控制代碼
        //這樣以後可以直接用mHandler.sendMessage的方式將任務直接放到背景工作執行緒了。
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        mServiceLooper = thread.getLooper();        mServiceHandler = new ServiceHandler(mServiceLooper);    }    @Override    public void onStart(Intent intent, int startId) {
        //從訊息佇列中擷取一個訊息,一般都是用這種方式初始化一個訊息,而不是用new message()形式
        //效率更高,代碼更健壯        Message msg = mServiceHandler.obtainMessage();        msg.arg1 = startId;//        msg.obj = intent;//這個就是startService的時候傳入的Intent了,        mServiceHandler.sendMessage(msg);//將包含請求內容Intent的message傳入到背景工作執行緒中    }    /**     * You should not override this method for your IntentService. Instead,     * override {@link #onHandleIntent}, which the system calls when the IntentService     * receives a start request.     * @see android.app.Service#onStartCommand     */    @Override    public int onStartCommand(Intent intent, int flags, int startId) {
        //注意調用了onStart,和它傳入的值。        onStart(intent, startId);        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;    }    @Override    public void onDestroy() {        mServiceLooper.quit();    }    /**     * Unless you provide binding for your service, you don't need to implement this     * method, because the default implementation returns null.      * @see android.app.Service#onBind     */    @Override    public IBinder onBind(Intent intent) {        return null;    }    /**     * This method is invoked on the worker thread with a request to process.     * Only one Intent is processed at a time, but the processing happens on a     * worker thread that runs independently from other application logic.     * So, if this code takes a long time, it will hold up other requests to     * the same IntentService, but it will not hold up anything else.     * When all requests have been handled, the IntentService stops itself,     * so you should not call {@link #stopSelf}.     *     * @param intent The value passed to {@link     *               android.content.Context#startService(Intent)}.     */    protected abstract void onHandleIntent(Intent intent);}

從線程分析:

如果是自訂IntentService的話,可以在函數中列印Thread.currentThread().getName()將當前所線上程列印出來。就會發現,只有onHandleIntent的執行是在另外一個新線程中,其他函數(onCreate/onStart/onStartCommand等)的執行都是在main線程(主線程的名稱)中。


範例程式碼:

實際的代碼參考如下:

package com.example.fmdemo;import android.app.IntentService;import android.content.Intent;import android.os.IBinder;import android.util.Log;public class IntentServiceDemo extends IntentService {private static final String TAG = "IntentServiceDemo";public IntentServiceDemo() {super("IntentServiceDemo");}public IntentServiceDemo(String name) {super(name);// TODO Auto-generated constructor stub}@Overrideprotected void onHandleIntent(Intent arg0) {// TODO Auto-generated method stubString action = arg0.getExtras().getString("param");if ("oper1".equals(action)) {Log.i(TAG, "onHandleIntent oper1 threadname = "+ Thread.currentThread().getName());} else if ("oper2".equals(action)) {Log.i(TAG, "onHandleIntent oper2 threadname = "+ Thread.currentThread().getName());}try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubLog.i(TAG, "onBind threadname = " + Thread.currentThread().getName());return super.onBind(intent);}@Overridepublic void onCreate() {// TODO Auto-generated method stubLog.i(TAG, "onCreate threadname = " + Thread.currentThread().getName());super.onCreate();}@Overridepublic void onDestroy() {// TODO Auto-generated method stubLog.i(TAG, "onDestroy threadname = " + Thread.currentThread().getName());super.onDestroy();}@Overridepublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubLog.i(TAG, "onStart threadname = " + Thread.currentThread().getName());super.onStart(intent, startId);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubLog.i(TAG, "onStartCommand threadname = "+ Thread.currentThread().getName());return super.onStartCommand(intent, flags, startId);}@Overridepublic void setIntentRedelivery(boolean enabled) {// TODO Auto-generated method stubLog.i(TAG, "setIntentRedelivery threadname = "+ Thread.currentThread().getName());super.setIntentRedelivery(enabled);}}

在自訂的Activity的onCreate中添加如下代碼:

Intent startServiceIntent = new Intent("com.example.fmdemo.intentservice");Bundle bundle = new Bundle();bundle.putString("param", "oper1");startServiceIntent.putExtras(bundle);startService(startServiceIntent);Intent startServiceIntent2 = new Intent("com.example.fmdemo.intentservice");Bundle bundle2 = new Bundle();bundle2.putString("param", "oper2");startServiceIntent2.putExtras(bundle2);startService(startServiceIntent2);

運行結果如下:

07-01 06:58:23.557: I/IntentServiceDemo(3732): onCreate threadname = main07-01 06:58:23.571: I/IntentServiceDemo(3732): onStartCommand threadname = main07-01 06:58:23.571: I/IntentServiceDemo(3732): onStart threadname = main07-01 06:58:23.576: I/IntentServiceDemo(3732): onHandleIntent oper1 threadname = IntentService[IntentServiceDemo]07-01 06:58:23.577: I/IntentServiceDemo(3732): onStartCommand threadname = main07-01 06:58:23.577: I/IntentServiceDemo(3732): onStart threadname = main07-01 06:58:25.577: I/IntentServiceDemo(3732): onHandleIntent oper2 threadname = IntentService[IntentServiceDemo]07-01 06:58:27.579: I/IntentServiceDemo(3732): onDestroy threadname = main

可以看到onHandleIntent是在不同main主線程的背景工作執行緒中啟動並執行。

IntentService使用比較簡單,但是實現機制比較有趣。感興趣的同學可以自己把代碼敲進去看看。


參考文章:

1. Android中IntentService的原理及使用

2. IntentService

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.