天天看點

Android IntentService源碼解讀

說到IntentService,其實他内部也是一個Thread + Handler實作的,之前我們在閱讀源碼,讓你徹底了解AsyncTask運作原理這篇中我們就說過,他的原型其實也是Thread+Handler,對吧。隻不過這個Thread有點特别,怎麼個特别法呢?這個線程run()方法執行是擷取建立Looper的操作,而平常呢,我們看看線程run()方法裡,一般是執行一些耗時操作的對吧,比如我Asynbctask裡面就是這樣的。好了,不多說,下面我們來閱讀閱讀IntentService的源碼。

IntentService是一種特殊的Service,他繼承了Service,而且它還是一個抽象類,是以,你作為一個開發者,就必須是他的子類才能使用它,順便還說一句,有的面試官會問你,抽象類能不能繼承非抽象類,那麼你看了IntentService這個類,那你的回答又會是什麼呢?哈哈!答案顯而易見,是可以的,對不?IntentService可用于執行背景的耗時操作,而且當他執行完相關的任務時,他就會停止自己,這也是Google官方給出優化應用記憶體中的一種方法。這個道理也很明顯,當你不需要一個常駐後,讓他執行完他的任務之後,就釋放記憶體,節省記憶體開銷,這對一個開發者來說,是一個良好的習慣。好,我們先來看看IntentService中的onCreate()方法:

@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();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

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

你看看,他裡面做了什麼?首先,這onCreate()方法裡建立了一個HandlerThread線程,這個HandlerThread裡面做了什麼,你暫時不要管,如果你想知道,你可以去先去看看這篇關于HandleThread的源碼解讀 HandleThread源碼分析,其實HandlerThread主要的事情就是構造一個Looper執行個體,通過它得到這個Looper執行個體,通過Looper來構造一個ServiceHandler執行個體,那麼,通過這個mServiceHandler發送的消息始終會在ServiceHandler裡面去執行,當然,它也可以用于執行背景的任務,每次啟動IntentService時,它的onStrartCommand()方法都會被調用一次,IntentService在onStartCommand()方法中處理每一個背景任務的Intent,下面我們看看,onStartCommand()中是如何處理外部的Intent的,它内部調用了onStart()方法,那我們就來看看onStart()方法内部的實作,如下所示:

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

    /**
     * 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(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
           

從上面代碼可以看出,IntentService僅僅是通過mService發出一個消息,這個消息會在ServiceHandler中處理,mServiceHandler收到消息後,它會把這個Intent對象傳遞給onHandleIntent()方法去處理。注意,這裡這個Intent對象跟你外部傳來的Intent對象完全一緻,通過這個Intent對象就可以解析在外部啟動IntentService所傳過來的相關參數,然後你通過這些參數就能區分具體的背景任務,這樣在onHandleIntent()方法中就可以對不同的背景人物做處理了。當onHandleIntent()方法執行完之後,它就會調用stopSelf(int startId)方法來停止掉服務,那麼這裡采用stoptSelf(int startId)而不采用stopSelf()方法,那是因為,stopSelf()方法會立刻将服務停止掉,假如說某個時候,還有消息未處理,那怎麼辦?如果你調用stopSelf()方法的話,那麼後面的消息,你将無法處理,這樣,對我們來說是我們不想要的,而onStopSelf(int startId)就能幫我們解決這個問題,這個方法呢,會等待所有的消息處理完,才會将服務停止掉。

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

  我們知道,onHandleIntent()方法是一個抽象方法,在Java中,如果某個類有抽象方法那麼這個類必須聲明為抽象,抽象類中可以有抽象方法,也可以有實作的方法,是以呢,這個類是抽象類,那麼我們就需要子類來實作這個抽象方法,他的作用是從Intent區分具體的任務并執行這些任務。如果目前背景之後一個任務,那麼onHandleIntent()方法執行完成之後,服務就會停止掉,如果此時背景有多個任務時,那麼當onHandleIntent執行完最後一個任務時,才會将服務停止掉。在IntentService中,我們執行一個背景任務,就需要啟動一次IntentService,而IntentService内部又是通過消息的方式想HandleThread來請求執行任務的,而這個Looper中取出消息的消息也是有序的,那麼我就可以猜測出,他的任務也是按照你啟動IntentService的背景任務的順序來執行的。如果有對Handler内部機制不熟的,可以看看這篇 閱讀源碼,讓你徹底了解Handler、Message、Looper之間的關系博文。

下面,我們将通過一個例子來說明當需要在背景執行多個任務的情況,到底是不是要執行完所有的任務之後,才回去停掉服務。代碼如下:

public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";

    public MyIntentService(){
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        String action = intent.getStringExtra("task_action");
        Log.e(TAG, "receive task" + action);
        SystemClock.sleep(5000);

        if("com.qhb.action.TASK1".equals(action)){
            Log.e(TAG,"handle task : "+action);
        }
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG,"service destroyed");
    }
           

實踐結果,我就不貼了,不知道android studio為毛突然列印不出日志了,沒法示範了,不過,大家可以自己動手試試。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Intent intent = new Intent(this,MyIntentService.class);
        intent.putExtra("task_action", "com.qhb.action.TASK1");
        startService(intent);

        intent.putExtra("task_action","com.qhb.action.TASK2");
        startService(intent);

        intent.putExtra("task_action","com.qhb.action.TASK3");
        startService(intent);

        intent.putExtra("task_action", "com.qhb.action.TASK4");
        startService(intent);
    }
}
           

具體的都給貼上了,大家隻要建立工程,複制黏貼到裡面即可運作,非常不好意思,并不是我偷懶,不知道studio出什麼毛病了。

這裡順便說一下,Service與IntentService的差別就是能否執行耗時操作而已。

歡迎大家拍磚、吐槽。