Android IntentService源碼分析

概述

大家知道,普通Service服務是運行在UI線程上的,這就意味着如果我們需要通過Service執行一些耗時的操作,我們必須要通過創建一個工作線程來完成,否則應用可能會出現ANR異常。

IntentService就是爲了解決這個問題而出現的。IntentService是Service的一個子類,該類的作用就是可以讓服務在工作線程中執行任務,而不需要自行創建工作線程。

IntentService的主要作用(優點):
1. 在IntentService中會默認創建工作線程用於執行傳遞的Intent,這樣在執行耗時操作時不需要手動去創建線程了
2. 在IntentService中創建工作隊列,用於將 Intent 逐一傳遞給 onHandleIntent() 實現,這樣就永遠不必擔心多線程問題。
3. 在處理完所有啓動請求後停止服務,因此您永遠不必調用 stopSelf()。
4. IntentService的onBind方法默認返回null

IntentService源碼分析

在IntentService中,主要使用到了HandlerThread。HandlerThread是Thread的一個子類,在該類中可以使用Handler。其實HandlerThread的實現原理非常簡單,就是在run方法中通過Looper.prepare()來創建消息隊列,然後通過Looper.loop()方法開啓消息循環,整個實現流程如同ActivityThread.main()方法中MainLooper的初始化過程。

具體關於HandlerThread的介紹,請看 Android HandlerThread源碼分析

IntentServcie源碼分析

public abstract class IntentService extends Service {

    /**
     * 1、在IntentServcie被首次創建時,會執行onCreate方法
     */
    @Override
    public void onCreate() {
        super.onCreate();
        // 1、創建一個HandlerThread,用於接收消息
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        // 2、獲取上面HandlerThread的實例的looper
        mServiceLooper = thread.getLooper();

        // 3、通過HandlerThread的looper,創建一個handler對象mServiceHandler,這樣通過mServiceHandler發送的對象都會在HandlerThread中被處理
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }


    /**
     * 2、每次啓動IntentServcie, onStartCommand方法會被調用,該方法內部主要調用onStart方法
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    /**
     * 3、在onStrat方法中主要是通過mServiceHandler發送了一條消息。
     * <p>
     * 在mServiceHandler發送的消息中,intent對象會作爲發送消息的參數(這裏的intent和通過startServcie方法傳遞的intent是同一個對象)
     * <p>
     * 同時,消息中會被攜帶一個startId的參數,該參數主要用於判斷服務是否結束
     */
    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }


    /**
     * 4、ServiceHandler,該handler對象是通過HandlerThread的looper創建的,所以通過ServiceHandler
     * 發送的消息都會被髮送到HandlerThread中執行,由於HandlerThread是一個Thread類,這樣就實現了在IntentService
     * 無需創建一個Thread來執行後臺耗時任務。
     * <p>
     * 同時,由於ServiceHandler內部的消息隊列是通過looper維護的,這樣就保證了消息隊列是順序執行的,所以IntentService也是
     * 順序執行任務的。
     */
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            /*
             * 1、抽象方法,需要在子類中實現具體後臺任務的實現
             */
            onHandleIntent((Intent) msg.obj);

            /*
             * 2、在任務執行完成,自動停止服務。
             *
             * msg.arg1 就是在startId,這是爲每一消息生成的唯一標識。每通過IntentService處理一個請求時,
             * 都會有一個消息被放入到消息隊列中,只有當最後一個消息執行完成即msg.arg1等於最後一個放入到消息隊列的startId,
             * 服務纔會被停止,否者IntentService不會被停止
             *
             * 這樣做的好處就是:保證消息隊列中的所有消息都被處理,服務纔會被停止。
             *
             */
            stopSelf(msg.arg1);
        }
    }

    /**
     * 5、抽象方法,該方法需要在IntentService的子類中實現,也是IntentService中唯一一個需要實現的方法
     *
     * @param intent
     */
    protected abstract void onHandleIntent(Intent intent);


    @Override
    public void onDestroy() {
        // 退出消息隊列循環
        mServiceLooper.quit();
    }

    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        // 默認返回null
        return null;
    }


}

IntentService的簡單使用

這裏通過IntentService模擬一個簡單的下載任務。


public class IntentServcieActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_servcie);

        Button button = findViewById(R.id.btn);
        button.setOnClickListener(new View.OnClickListener() {
            private int urlid;
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(IntentServcieActivity.this, DownloadService.class);
                intent.putExtra(DownloadService.DOWN_URL, "url" + ++urlid);
                startService(intent);
            }
        });
    }
}


/**
 * 通過IntentService完成下載任務
 */
public class DownloadService extends IntentService {
    public static final String DOWN_URL = "down_url";
    public DownloadService() {
        super("DownloadService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String url = intent.getStringExtra(DOWN_URL);
        downlaod(url);
    }

    /**
     * 模擬下載任務
     */
    private void downlaod(String url) {
        Log.e("zhangke", "url = " + url + "  正在下載中...");
        SystemClock.sleep(3000);
        Log.e("zhangke", "url = " + url + "  下載完成");
    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章