IntentService繼承了Service並且是一個抽象類,需要創建它的子類才能使用IntentService。它相對Service來說,是一個特殊的Service,它的內部使用HandleThread
來執行服務,任務執行完,IntentService會自動退出。相對於Thread來說,它是一個服務,它的優先級高於線程,不容易被系統回收。
一個面試問題:我要用服務下載apk,是用IntentService,還是Service好?爲什麼?
IntentService與Service都可以執行下載apk的任務。具體的下載代碼可以觀看我的文章:IntentService、Service下載的apk。在回答這可問題之前我們要再次回顧一下Service的概念。Service是一種計算型組件,用於在後臺執行一系列計算任務。Service不是一個線程,儘管它是執行後臺計算的,它是運行在主線程中,耗時的後臺操作仍然需要在單獨的子線程中去執行,所以不要在Service的onStart方法中執行耗時操作,不然會出現Application Not Responding!的異常。而IntentService採用隊列的方式將請求的Intent加入隊列,然後開啓一個線程來處理隊列中的Intent,對於異步的startService請求。IntentService處理完一個後再處理第二個,都是在子線程中,不會阻塞主線程。所以有耗時操作與其在Service裏開啓子線程不如在IntentService中處理耗時操作。
回到主題,繼續分析IntentService。
在IntentService的onCreate()方法中,可以看到它實現了HandleThread 和Handle。
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
@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);
}
IntentService第一次啓動時,onCreate()方法調用,創建一個HandlerThread,獲取到mServiceLooper,mServiceHandler。通過mServiceHandler發送信息會在HandlerThread中執行。每次啓動IntentService,會調用onStartCommand()。IntentService在onStartCommand()方法中處理後臺的Intent。在源碼中onStartCommand調用了onStart():
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
IntentService通過mServiceHandler發送了一條信息,消息會在HandleThread方法中處理。同時將Intent對象給 ServiceHandler的onHandleIntent方法處理。onHandleIntent是運行在子線程中,可以做耗時操作。另外這裏的Intent對象和外界startService(intent)保持一致,通過它可以獲得外界啓動IntentService傳遞的參數,可以區分具體的後臺任務,對不同的後臺採取不同的處理方式(可以咱參照文章後邊的樣例)。onHandleIntent方法執行完之後,會調用stopSelf(int startId)停止服務。stopSelf()會立即停止服務,stopSelf(int startId)會等待所有信息都處理完後才關閉服務,它在服務關閉前會判斷最近啓動的次數是否與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);
}
}
//This method is invoked on the worker thread with a request to process.
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
onHandleIntent是一個抽象方法,需要在子類中實現,它的作用就是區分Intent中的參數來區分任務並執行。在執行完onHandleIntent方法後,如果目前只有一個後臺任務會立刻調用stopSelf(int startId)停止服務。如果有多個,會在onHandleIntent執行完最後一個任務後調用停止服務。每執行一個後臺任務都會啓動一次IntentService,而IntentService內部的信息是通過HandleThread來執行,Handle中的Looper順序處理信息,所以IntentService是順序執行後臺任務的。多後臺任務會按照外界發起的順序排隊執行。
public class DemoIntentService extends IntentService {
static final String Tag = "DemoIntentService";
public DemoIntentService() {
super("demo-intentService");
}
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getStringExtra("test_action");
Log.e(Tag, "receive action=====" + action);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
Log.e(Tag, "onDestroy=====");
super.onDestroy();
}
}
public class TestActivity extends Activity {
BroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent mIntent = new Intent(this, DemoIntentService.class);
mIntent.putExtra("test_action","action1");
startService(mIntent);
mIntent.putExtra("test_action","action2");
startService(mIntent);
mIntent.putExtra("test_action","action3");
startService(mIntent);
}
}
註冊列表
<service android:name=“.downloadApk.DemoIntentService"/>
打印結果:
05-16 23:53:12.219 18007-18292/? E/DemoIntentService: receive action=====action1
05-16 23:53:13.219 18007-18292/? E/DemoIntentService: receive action=====action2
05-16 23:53:14.219 18007-18292/? E/DemoIntentService: receive action=====action3
05-16 23:53:15.219 18007-18007/? E/DemoIntentService: onDestroy=====
日誌顯示三個後臺任務順序執行,在action3後,執行stopSelf(int startId)。
=====================================>
這是一篇對書筆記,文章內容大多數來自於androdi開發藝術探索,很不錯的一本書。