說到IntentService,其實他内部也是一個Thread + Handler實作的,之前我們在閱讀源碼,讓你徹底了解AsyncTask運作原理這篇中我們就說過,他的原型其實也是Thread+Handler,對吧。隻不過這個Thread有點特别,怎麼個特别法呢?這個線程run()方法執行是擷取建立Looper的操作,而平常呢,我們看看線程run()方法裡,一般是執行一些耗時操作的對吧,比如我Asynbctask裡面就是這樣的。好了,不多說,下面我們來閱讀閱讀IntentService的源碼。
IntentService是一種特殊的Service,他繼承了Service,而且它還是一個抽象類,是以,你作為一個開發者,就必須是他的子類才能使用它,順便還說一句,有的面試官會問你,抽象類能不能繼承非抽象類,那麼你看了IntentService這個類,那你的回答又會是什麼呢?哈哈!答案顯而易見,是可以的,對不?IntentService可用于執行背景的耗時操作,而且當他執行完相關的任務時,他就會停止自己,這也是Google官方給出優化應用記憶體中的一種方法。這個道理也很明顯,當你不需要一個常駐後,讓他執行完他的任務之後,就釋放記憶體,節省記憶體開銷,這對一個開發者來說,是一個良好的習慣。好,我們先來看看IntentService中的onCreate()方法:
@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);
}
你看看,他裡面做了什麼?首先,這onCreate()方法裡建立了一個HandlerThread線程,這個HandlerThread裡面做了什麼,你暫時不要管,如果你想知道,你可以去先去看看這篇關于HandleThread的源碼解讀 HandleThread源碼分析,其實HandlerThread主要的事情就是構造一個Looper執行個體,通過它得到這個Looper執行個體,通過Looper來構造一個ServiceHandler執行個體,那麼,通過這個mServiceHandler發送的消息始終會在ServiceHandler裡面去執行,當然,它也可以用于執行背景的任務,每次啟動IntentService時,它的onStrartCommand()方法都會被調用一次,IntentService在onStartCommand()方法中處理每一個背景任務的Intent,下面我們看看,onStartCommand()中是如何處理外部的Intent的,它内部調用了onStart()方法,那我們就來看看onStart()方法内部的實作,如下所示:
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
從上面代碼可以看出,IntentService僅僅是通過mService發出一個消息,這個消息會在ServiceHandler中處理,mServiceHandler收到消息後,它會把這個Intent對象傳遞給onHandleIntent()方法去處理。注意,這裡這個Intent對象跟你外部傳來的Intent對象完全一緻,通過這個Intent對象就可以解析在外部啟動IntentService所傳過來的相關參數,然後你通過這些參數就能區分具體的背景任務,這樣在onHandleIntent()方法中就可以對不同的背景人物做處理了。當onHandleIntent()方法執行完之後,它就會調用stopSelf(int startId)方法來停止掉服務,那麼這裡采用stoptSelf(int startId)而不采用stopSelf()方法,那是因為,stopSelf()方法會立刻将服務停止掉,假如說某個時候,還有消息未處理,那怎麼辦?如果你調用stopSelf()方法的話,那麼後面的消息,你将無法處理,這樣,對我們來說是我們不想要的,而onStopSelf(int startId)就能幫我們解決這個問題,這個方法呢,會等待所有的消息處理完,才會将服務停止掉。
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);
}
}
我們知道,onHandleIntent()方法是一個抽象方法,在Java中,如果某個類有抽象方法那麼這個類必須聲明為抽象,抽象類中可以有抽象方法,也可以有實作的方法,是以呢,這個類是抽象類,那麼我們就需要子類來實作這個抽象方法,他的作用是從Intent區分具體的任務并執行這些任務。如果目前背景之後一個任務,那麼onHandleIntent()方法執行完成之後,服務就會停止掉,如果此時背景有多個任務時,那麼當onHandleIntent執行完最後一個任務時,才會将服務停止掉。在IntentService中,我們執行一個背景任務,就需要啟動一次IntentService,而IntentService内部又是通過消息的方式想HandleThread來請求執行任務的,而這個Looper中取出消息的消息也是有序的,那麼我就可以猜測出,他的任務也是按照你啟動IntentService的背景任務的順序來執行的。如果有對Handler内部機制不熟的,可以看看這篇 閱讀源碼,讓你徹底了解Handler、Message、Looper之間的關系博文。
下面,我們将通過一個例子來說明當需要在背景執行多個任務的情況,到底是不是要執行完所有的任務之後,才回去停掉服務。代碼如下:
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public MyIntentService(){
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getStringExtra("task_action");
Log.e(TAG, "receive task" + action);
SystemClock.sleep(5000);
if("com.qhb.action.TASK1".equals(action)){
Log.e(TAG,"handle task : "+action);
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG,"service destroyed");
}
實踐結果,我就不貼了,不知道android studio為毛突然列印不出日志了,沒法示範了,不過,大家可以自己動手試試。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,MyIntentService.class);
intent.putExtra("task_action", "com.qhb.action.TASK1");
startService(intent);
intent.putExtra("task_action","com.qhb.action.TASK2");
startService(intent);
intent.putExtra("task_action","com.qhb.action.TASK3");
startService(intent);
intent.putExtra("task_action", "com.qhb.action.TASK4");
startService(intent);
}
}
具體的都給貼上了,大家隻要建立工程,複制黏貼到裡面即可運作,非常不好意思,并不是我偷懶,不知道studio出什麼毛病了。
這裡順便說一下,Service與IntentService的差別就是能否執行耗時操作而已。
歡迎大家拍磚、吐槽。