android 多線程 — IntentService

我們來看看android 上著名的一次性 Service IntentService ,IntentService 自帶一個線程,內部使用 HandlerThread 提供多線程服務。android 里面除了 AsyncTask ,其他的多線程基本都是用的 handle 、 looper 消息來做的,IntentService 也不例外啊,這樣我們更容易理解源碼。

IntentService 的使用


IntentService 需要我們去繼承,然后重寫 onHandleIntent 方法,接受我們發送過來的參數

public class MyIntentService extends IntentService {

    public MyIntentService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

        String value = intent.getExtras().getString("AAA");

        if ("AAA".equals(value)) {
            Log.d("AAA", Thread.currentThread().getName() + "接受到消息" + System.currentTimeMillis());
        }
    }
}

UI 線程啟動 IntentService 服務

Intent i = new Intent(this,MyIntentService.class);
Bundle bundle = new Bundle();
bundle.putString("taskName", "task1");
i.putExtras(bundle);
startService(i);

IntentService 因為里面用的也是 handle,looper 技術,所以也是可以接收多個消息的,我們可以多次執行上面的代碼來穿參數給 IntentService 對象,此時會觸發 IntentService 的 onStartCommand() 方法

翻翻源碼吧


既然 IntentService 用的 handle,那么源碼就不難理解了。

IntentService 聲明的成員變量,可以看到有一個 looper 消息隊列和給 looper 發送消息的 handle

public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;

構造方法沒干什么事

    public IntentService(String name) {
        super();
        mName = name;
    }

onCreate 初始化函數

    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 的 looper 構建了用于內部通信的 handle 出來

onStartCommand 函數會調用 onStart 函數,把 intent 作為參數包裝成一個 message 消息,然后用這個內部通信的 handle ,把這個 message 發送到內部線程 HandlerThread 的消息隊列里面去執行

    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

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

然后我們來看看 IntentService 內部定義的這個用于信息通信的 handle 類型

    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 在接受到消息時會執行我們重寫的 onHandleIntent 方法,在方法執行完成后,會嘗試關閉當前所在服務,但是任務隊列不為 null 的話是不會關閉服務的,這里就得去看 service 的源碼了,stopSelf 是 service 提供的方法

這是 IntentService 的工作流程圖


944365-fa5bfe6dffa531ce.png

IntentService 有人不建議用 bindService 啟動,因為不會走 onStartcommand 函數,不會往內內部 HandlerThread 線程的消息隊列里添加任務,需要我們自己手動添加。

最后了,感覺 IntentService 現在使用的場景很少啊, 也就看到有人用在版本更新上,但是要是需要對版本更新的后太 Service 有更多操作的話, IntentService 是不太適合的,自己寫一個 Service 服務,然后在里面用 Rxjava 跑多線程任務要比 IntentService 靈活的多,還能用 binder 和 service 單向通信。

參考資料:


?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容