前言
IntentService
本質上也屬于
Service
,它可以說是一個使用起來更為簡單的
Service
。在我們基本的
Service
使用過程中,我們需要在
Service
中自己開啟子線程進行耗時操作,并且在
Service
執行結束後還要調用
stopSelf
或
stopService
方法來關閉
Service
,而使用
IntentService
的話,這些問題将通通不需要關注。因為
IntentService
内部就是預設執行在子線程中的,并且在執行結束後它會幫我們自動停止
Service
。
在學習本章知識的時候,你需要先知曉以下知識點:
- Service的基本使用
- 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
的源碼還是比較少的,隻要對基本的
Service
以及 Android 的異步消息處理機制夠熟悉,了解它的實作還是比較容易的,希望大家能夠通過這篇文章有所收獲,有問題的話可以在下方評論區給我留言。