異步處理老司機:IntentService 源碼分析

IntentService 介紹

IntentService 是一種特殊的 Service,它繼承了 Service 並且它是一個抽象類,因此必須創建它的子類才能夠使用 IntentService。它可用於執行後臺耗時任務,當任務執行完成後它會自動停止,在資源不足時,系統會對一些被認為時無用的資源給清理掉,由於它是 Service 的原因,它的優先級比單純的線程的優先級高很多,不容易被系統殺死(清理掉),所以它適合執行一些高優先級的後臺任務。在實現上,IntentService 封裝了 Handlerhread 和 Handler。

HandlerThread 繼承了 Thread,它是一種可以使用 Handler 的 Thread。它的實現是通過在run()方法中通過Looper.prepare()來創建消息隊列,並通過Looper.loop()方法來開啟消息循環, 它的內部對Thread 的 run 方法進行重寫,通過Handler的消息方式(Looper循環)來通知HandlerThread執行一個具體的任務。

<code>@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/<code>

在明確了不需要使用HandlerThread的時,可以通過它的quit或者quitSafely方法來終止線程的執行

<code>public boolean quit() {
Looper looper = getLooper();

if (looper != null) {
looper.quit();
return true;
}
return false;
}

public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/<code>

這兩個方法的區別是:

quit()使用此方法可能是不安全的,因為在Looper隊列終止之前可能無法傳遞某些消息。

quitSafely()使用此方法可能是安全的,因為一旦已經傳遞消息,隊列中的所有剩餘消息被處理,方法就會終止。然而,在循環終止之前,延遲的消息將在未來的到期時間內不傳遞。

從源碼來分析 IntentService 的執行順序

在onCreate()初始化HandlerThread和ServiceHandler,用於在後面調用onStart後來發送消息。

<code>@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);
}
/<code>

每次啟動服務都會調用一次onStartCommand()方法,並且它會調用onStart()

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

在onStart()中發送消息

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

後臺任務是順序執行的因為 Handler 中的 Looper 是順序處理消息。

任務執行完成之後結束服務:

<code>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); 而不使用 stopSelf();
// 是因為 stopSelf() 會立即停止服務,
// 而 stopSelf(msg.arg1); 在停止服務前會先判斷最近啟動服務的次數是否和 startId 相等

// 如果相等就歷經停止服務,不想動則不停止服務
stopSelf(msg.arg1);
}
}
/<code>

IntentService 使用

創建一個實例繼承自 IntentService

<code>public class TestIntentService extends IntentService {
private static final String TAG = "TestIntentService";

public TestIntentService() {
super(TAG);
Log.e(TAG, "TestIntentService: " );
}

@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: " );
}

@Override
protected void onHandleIntent(@Nullable Intent intent) {
String taskAction = intent.getStringExtra("task_action");
SystemClock.sleep(3000);
Log.e(TAG, "onHandleIntent: "+taskAction);
}

@Override
public void onDestroy() {
Log.e(TAG, "onDestroy: service destory" );
super.onDestroy();
}
}
/<code>

註冊服務在AndroidMainfest.xml中註冊服務

<code><service>
/<code>

開啟服務

<code>Intent intent = new Intent(CallBackTestActivity.this, TestIntentService.class);
intent.putExtra("task_action","com.dx.action.TASK1");
// 開啟第一個服務
startService(intent);
intent.putExtra("task_action","com.dx.action.TASK2");
// 開啟第二個服務
startService(intent);
intent.putExtra("task_action","com.dx.action.TASK3");
// 開啟第三個服務
startService(intent);
/<code>

輸出結果是:

異步處理老司機:IntentService 源碼分析

從截圖中的時間,以及輸出順序正好驗證了上面的敘述!ok,完工~

原創作者:龍衣襲,原文鏈接:https://www.jianshu.com/p/92c8a4451bb0


分享到:


相關文章: