天天看點

Service與BroadcastReceiver——(4)IntentService

前面介紹的Service在官方文檔介紹中說Service存在着如下兩個問題:

1.A Service isnota separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.

2.A Service isnota thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).

1、Service不會專門啟動一條單獨的程序,Service與它所在的應用在同一個程序中。

2、Service不是專門一條新的線程,是以不能再Service中直接處理耗時任務。

如果開發者在Service中處理耗時任務,建議在Service中另外啟動一條新的線程來處理耗時的任務,可能有的朋友就會問:“既然在Service中處理耗時任務需要啟動新線程,為什麼我們不直接在Activity中開啟一個新線程,而要使用Service呢?”

其實這種在Activity中直接啟動一個線程來實作對有些業務邏輯是非常不可靠的,比如:使用者使用BroadcastReceiver來啟動一個新線程,BroadcastReceiver的生命周期非常短,這樣就可能存在這樣的問題,在子線程還沒有結束的情況下,BroadcastReceiver已經結束了,或者使用者在Activity中啟動一個新線程後直接退出,此時它們所在的程序就變成了空程序(沒有任何活動元件的程序),系統需要記憶體時可能會優先終止該程序。如果宿主程序被終止,那麼該程序内的所有子線程也會被終止,這樣就有可能導緻一些嚴重錯誤。

IntentService是Service的子類,是以它比Service增加了額外的功能,它正好彌補了Service的上述兩點不足:IntentService将會使用隊列來管理請求Intent,每當用戶端代碼通過Intent請求啟動IntentService時,IntentService會将該Intent加入隊列中,然後開啟一條新的worker線程來處理該Intent.對于異步的startService()請求,IntentService會按次序依次處理隊列中的Intent,該線程保證同一時刻隻處理一個Intent.由于IntentService使用新的worker線程處理Intent請求,是以IntentService不會阻塞主線程,是以IntentService就可以處理耗時任務。

IntentService有如下特征:

1、會建立單獨的worker線程來處理所有的Intent請求。

2、會建立單獨的worker線程來處理onHandleIntent()方法實作的代碼。

3、所有請求處理完成後,IntentService會自動停止,是以開發者無須調用stopSelf()方法

4、為Service的onBind()方法提供了預設的實作,預設實作的onBind()方法傳回null

5、為Service的onStartCommand()方法提供了預設實作,該實作會将請求的Intent添加到隊列中。

從上面的特點中可以看出來,擴充的IntentService實作Service無須重寫onBind()方法和onStartCommand()方法,隻要重寫onHandleIntent()方法即可。

下面通過一個具體例子來說明IntentService和Service的差別:

(1)繼承自Service的MyService類

package com.example.testservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MyService extends Service{

	@Override
	public IBinder onBind(Intent intent) {
		
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		//該方法内可以執行耗時任務,比如下載下傳檔案等
		long endTime = System.currentTimeMillis() + 20 * 1000;
		System.out.println("onStart");
		while(System.currentTimeMillis() < endTime){
			synchronized (this) {
				try {
					wait(endTime - System.currentTimeMillis());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println("--耗時任務執行完畢--");
		return START_STICKY;
	}
}
           

讀者可能會注意到onStartCommand方法最後的傳回值我設定成了START_STICKY,有關傳回值的詳細設定及含義将在下一篇文章中介紹。

執行結果

Service與BroadcastReceiver——(4)IntentService

可以看到在Service中執行耗時任務程式的主UI會被阻塞,出現ANR異常。

(2)繼承自IntentService的MyIntentService類

package com.example.testservice;

import android.app.IntentService;
import android.content.Intent;

public class MyIntentService extends IntentService{

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

	@Override
	protected void onHandleIntent(Intent arg0) {
		//該方法内可以執行耗時任務,比如下載下傳檔案等
		long endTime = System.currentTimeMillis() + 20 * 1000;
		System.out.println("onStart");
		while(System.currentTimeMillis() < endTime){
			synchronized (this) {
				try {
					wait(endTime - System.currentTimeMillis());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println("--耗時任務執行完畢--");
	}
}
           

執行結果:

Service與BroadcastReceiver——(4)IntentService