天天看點

IntentService 的使用與解析前言IntentService 的使用源碼分析

前言

IntentService

本質上也屬于

Service

,它可以說是一個使用起來更為簡單的

Service

。在我們基本的

Service

使用過程中,我們需要在

Service

中自己開啟子線程進行耗時操作,并且在

Service

執行結束後還要調用

stopSelf

stopService

方法來關閉

Service

,而使用

IntentService

的話,這些問題将通通不需要關注。因為

IntentService

内部就是預設執行在子線程中的,并且在執行結束後它會幫我們自動停止

Service

在學習本章知識的時候,你需要先知曉以下知識點:

  1. Service的基本使用
  2. Android的異步消息處理機制

如果你對這兩塊知識點還不夠熟悉的話,可以點選上面的超連結進行學習,那麼接下來就讓我們開始

IntentService

的學習吧,首先我們學習一下它的使用。

IntentService 的使用

IntentService

的使用和

Service

非常的相似,也比

Service

更加簡單,我們接下來建立一個

MyIntentService

類,并繼承自

IntentService

。它的代碼如下:

public class MyIntentService extends IntentService {

    private static final String TAG = MyIntentService.class.getSimpleName();

    public MyIntentService() {
        super("MyIntentService");
    }

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

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.d(TAG, "onHandleIntent's thread: " + Thread.currentThread());
    }

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

}
           

我們對裡面的 3 個生命周期中的方法進行重寫,它們分别是

onCreate

onHandleIntent

onDestroy

。如果你之前學習過

Service

的話,對

onCreate

onDestroy

應當是相當熟悉的了,它們就是分别對應于

IntentService

啟動時和停止時的方法。而

onHandleIntent

則比較陌生了,其實這個方法就是我們在

IntentService

中執行主要邏輯的方法,它預設是運作在子線程中的。這裡我們對這 3 個方法隻是簡單地列印

Log

,特别的我們會列印出

onHandleIntent

的線程,驗證它是否真的運作在子線程中。

接下來我們就為

MainActivity

中添加一個按鈕,通過按鈕來調用

startService

方法來啟動我們的

IntentService

,代碼如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button startServiceBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("MainActivity", Thread.currentThread().getName());
        setContentView(R.layout.activity_main);
        startServiceBtn = (Button)findViewById(R.id.start_service);
        startServiceBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start_service:
                Intent startIntent = new Intent(this, MyIntentService.class);
                startService(startIntent);
                break;
        }
    }
}
           

這段代碼邏輯相當簡單,這裡就不再做過多贅述了,我們在

Activity

onCreate

方法中也通過

Log

列印了線程的名字,運作程式,輸出結果如下:

D/MainActivity: main

D/MyIntentService: onCreate

D/MyIntentService: onHandleIntent’s thread: Thread[IntentService[MyIntentService],5,main]

D/MyIntentService: onDestroy

可以看到,

onHandleIntent

所處的線程與主線程名稱不同,說明它确實是運作在子線程房中的。并且在運作完畢之後,運作了

onDestroy

方法,也證明

IntentService

在運作結束後确實會自動進行停止。

在通過例子驗證了

IntentService

之後,我們接下來從源碼的層面分析它是如何實作這些特性的。

源碼分析

由于

IntentService

的源碼量不算多,隻有一百來行,是以這裡我就直接将它都貼了過來逐漸分析。它的源碼如下:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    
	......

    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}
           

首先我們知道了這是一個繼承自

Service

的抽象類,而它的抽象方法其實隻有一個,就是

onHandleIntent

方法,它是我們實作具體邏輯的地方,就是需要我們自己去重寫的。

接着我們看到它的成員

mServiceLooper

mServiceHandler

,它們分别是

Looper

類型和

ServiceHandler

類型的對象,而

ServiceHandler

又是繼承自

Handler

的,看到這裡我們應該非常熟悉了,它就是利用 Android 的異步消息處理機制來切換我們的線程的。

我們來看看

ServiceHandler

的實作代碼:

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

可以看到它的構造方法就是将一個

Looper

對象傳給父類的構造方法進行

Handler

的初始化。

接着看到

handleMessage

方法,在這裡會調用

onHandleIntent

方法,它就是在我們的自定義

IntentService

中被實作的嘛,然後在它執行完之後會調用

stopSelf

方法停止

Service

,這也就是我們之前所說的

IntentService

在執行完之後會自動停止的原因了。那麼我們隻要找到了通過

mServiceHandler

發送消息的地方,我們就找到了關鍵的地方了。

接下來我們繼續看到

onCreate

方法,它的代碼如下:

@Override
public void onCreate() {
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

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

我們看到第 3 行,這裡建立了一個

HandlerThread

對象

thread

,我們來看看這個類的實作是什麼樣子的:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

	......
}
           

可以看到,它是繼承自

Thread

的一個類,它内部同樣也維護了兩個重要的成員

mLooper

mHandler

。我們直接看到它的

run

方法:

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

可以看到

run

方法中所做的工作其實就是通過

Looper.prepare

方法建立一個

Looper

對象,然後在同步塊中通過

Looper.myLooper

指派給

mLooper

,緊接着在最後調用

Looper.loop

方法進入一個循環。

我們接着看到

getLooper

方法的實作:

public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }
    
    // If the thread has been started, wait until the looper has been created.
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}
           

這個方法做的工作也很簡單,首先判斷該線程是否還存活,不存活的話直接傳回

null

,如果還存活的話,會在下面的同步塊中判斷

mLooper

對象是否已經建立,如果還未建立并且線程此時還存活的話,就會調用

wait

方法進入等待狀态知道

mLooper

對象被建立為止,然後傳回

mLooper

這裡特别提到一點:既然有

wait

方法,那麼肯定就要有

notify

notifyAll

方法。我們可以發現整個

HandlerThread

中隻有在

run

方法中有一個

notifyAll

方法,它位于

mLooper = Looper.myLooper();

這句代碼之後。這麼做的原因是我們的

Handler

一般是在 UI 線程中建立的(

IntentService

同樣也是這麼做的),也就是說,我們必須等到

mLooper

建立完成,才能正确的傳回

getLooper

wait

notifyAll

就是為了解決這兩個線程的同步問題。

最後我們看到

HandlerThread

quit

方法:

public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}
           

這個方法首先通過

getLooper

擷取到

mLooper

,如果不為空的話,就會執行

Looper

quit

方法來終止

Looper

,進而停止依賴于該

Looper

Handler

的工作。

在分析完

HandlerThread

的代碼之後,我們繼續回到

IntentService

onCreate

方法,為了友善觀看這裡我們就直接把它貼了過來:

@Override
public void onCreate() {
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

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

首先構造出一個

HandlerThread

對象,然後通過

start

方法開啟了這個子線程,執行它的

run

方法,它的

run

方法我們前面分析過,會在這個子線程中建立一個

Looper

對象然後指派給

HandlerThread

的成員

mLooper

。緊接着

mServiceLooper

通過

HandlerThread

getLooper

方法指派,

getLooper

其實就是傳回

HandlerThread

mLooper

成員。最後

mServiceHandler

mServiceLooper

作為參數傳進它的構造方法中進行初始化,完成了對

mServiceHandler

的建立。

onCreate

這裡我們也可以得出一個結論:

mServiceHandler

handleMessage

方法是在子線程中執行的,因為它依賴的

Looper

就是位于子線程中的嘛。

接下來我們看到

IntentService

onStartCommand

方法,我們在前面的例子中說到過啟動

IntentService

調用的就是

startService

方法,是以

onStartCommand

方法就會在

onCreate

方法後得到調用,它的實作如下:

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

可以看到,它調用了

onStart

方法,并将

intent

startId

作為參數傳了進去,我們接下來看看

onStart

方法做了什麼:

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

可以很清楚地看到

onStart

方法做的就是通過調用

mServiceHandler

sendMessage

方法發送消息了,然後就會調用

ServiceHandler

類中的

handleMessage

方法進行處理,在前面的分析中我們已經知道了

handleMessage

方法就是在子線程中調用

onHandleIntent

方法,這個方法是留待我們自己實作的,然後在執行完

onHandleIntent

方法之後就會調用

stopSelf

方法停止

Service

,這個方法最終調用的也是

onDestroy

方法,我們看到

onDestroy

方法的實作:

@Override
public void onDestroy() {
    mServiceLooper.quit();
}
           

可以看到它就是調用

Looper

quit

方法退出,然後使

mServiceHandler

的工作終止。

到這裡,我們對

IntentService

的源碼解析就結束了,我們對它進行一下總結:

  • IntentService

    是繼承自

    Service

    的一個類,它在内部維護了一個

    Looper

    類型的成員

    mServiceLooper

    ServiceHandler

    類型的成員

    mServiceHandler

    ,用于進行線程的切換。
  • IntentService

    通過

    startService

    方法啟動,是以它的生命周期應當是

    onCreate - onStartCommand - onDestroy

  • onCreate

    中進行了對

    mServiceLooper

    mServiceHandler

    的初始化,要注意到

    mServiceLooper

    是在子線程中運作的。
  • onStartCommand

    中調用了

    onStart

    方法,該方法通過

    mServiceHandler

    發送消息給

    ServiceHandler

    handleMessage

    方法進行處理。
  • ServiceHandler

    handleMessage

    方法調用了

    onHandleIntent

    方法和

    stopSelf

    方法,

    onHandleIntent

    方法就是我們需要自己實作的方法,

    stopSelf

    方法最終會調用到

    onDestroy

    方法,要注意到由于

    mServiceLooper

    是在子線程中運作的,是以

    handleMessage

    方法也是運作在子線程中的,同時它也實作了在

    IntentService

    運作完後自動停止

    Service

  • onDestroy

    中調用

    Looper

    quit

    方法退出

    mServiceLooper

    ,進而停止

    mServiceHandler

    的運作。

最後我們通過圖形的形式來從另一個角度總結

IntentService

IntentService 的使用與解析前言IntentService 的使用源碼分析

到這裡,我們

IntentService

相關的知識點就介紹完了,

IntentService

的源碼還是比較少的,隻要對基本的

Service

以及 Android 的異步消息處理機制夠熟悉,了解它的實作還是比較容易的,希望大家能夠通過這篇文章有所收獲,有問題的話可以在下方評論區給我留言。