IntentService為在單一后臺線程中執(zhí)行任務(wù)提供了一種直接的實現(xiàn)方式比默。它可以處理一個耗時的任務(wù)并確保不影響到UI的響應(yīng)性飞傀。另外IntentService的執(zhí)行還不受UI生命周期的影響线梗,以此來確保AsyncTask能夠順利運行胞皱。
但是IntentService有下面幾個局限性:
- 不可以直接和UI做交互俐巴。為了把他執(zhí)行的結(jié)果體現(xiàn)在UI上压汪,需要把結(jié)果返回給Activity力崇。
- 工作任務(wù)隊列是順序執(zhí)行的斗塘,如果一個任務(wù)正在IntentService中執(zhí)行,此時你再發(fā)送一個新的任務(wù)請求亮靴,這個新的任務(wù)會一直等待直到前面一個任務(wù)執(zhí)行完畢才開始執(zhí)行馍盟。
- 正在執(zhí)行的任務(wù)無法打斷。
雖然有上面那些限制茧吊,然而在在大多數(shù)情況下贞岭,IntentService都是執(zhí)行簡單后臺任務(wù)操作的理想選擇。
1.創(chuàng)建IntentService
創(chuàng)建一個IntentService組件搓侄,需要自定義一個新的類瞄桨,它繼承自IntentService,并重寫onHandleIntent()方法
注意
一個普通Service組件的其他回調(diào)讶踪,例如onStartCommand()會被IntentService自動調(diào)用芯侥。在IntentService中,要避免重寫那些回調(diào)。
public class MyService extends IntentService {
@Override
protected void onHandleIntent(Intent workIntent) {
dataString = workIntent.getDataString();
}}
2.在Manifest文件中定義IntentService
IntentService需要在manifest文件添加相應(yīng)的條目柱查。
注意
<service>標簽并沒有包含任何intent filter廓俭。因為發(fā)送任務(wù)給IntentService的Activity需要使用顯式Intent,所以不需要filter物赶。這也意味著只有在同一個app或者其他使用同一個UserID的組件才能夠訪問到這個Service白指。
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
<service
android:name=".MyService"
android:exported="false"/>
<application/>
3.創(chuàng)建任務(wù)請求并發(fā)送到IntentService
一旦執(zhí)行了startService(),IntentService在自己本身的onHandleIntent()方法里面開始執(zhí)行這個任務(wù)酵紫,任務(wù)結(jié)束之后告嘲,會自動停止這個Service。
mServiceIntent = new Intent(getActivity(), MyService.class);
mServiceIntent.setData(Uri.parse(dataUrl));
getActivity().startService(mServiceIntent);
4.利用IntentService 發(fā)送任務(wù)狀態(tài)
通過執(zhí)行LocalBroadcastManager.sendBroadcast()來發(fā)送Intent奖地。Intent被發(fā)送到任何有注冊接受它的組件中橄唬。為了獲取到LocalBroadcastManager的實例,可以執(zhí)行g(shù)etInstance()参歹。
Intent localIntent = new Intent(Constants.BROADCAST_ACTION)
.putExtra(Constants.EXTENDED_DATA_STATUS, status);
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
5.接收來自IntentService的狀態(tài)廣播
為了接受廣播的數(shù)據(jù)對象仰楚,需要使用BroadcastReceiver的子類并實現(xiàn)BroadcastReceiver.onReceive()的方法,這里可以接收LocalBroadcastManager發(fā)出的廣播數(shù)據(jù)犬庇。
private class ResponseReceiver extends BroadcastReceiver{
DownloadStateReceiver() { }
public void onReceive(Context context, Intent intent) {
}}
一旦定義了BroadcastReceiver僧界,也應(yīng)該定義actions,categories與data用過濾廣播臭挽。為了給系統(tǒng)注冊這個BroadcastReceiver和IntentFilter捂襟,需要通過LocalBroadcastManager執(zhí)行registerReceiver()的方法。
statusIntentFilter = new IntentFilter(Constants.ACTION_ZOOM_IMAGE);
LocalBroadcastManager.getInstance(getActivity())
.registerReceiver( mDownloadStateReceiver, mIntentFilter);
6.最后
使用LocalBroadcastManager結(jié)合IntentService其實是一種很典型高效的做法欢峰,同時也更符合OO的思想葬荷,通過廣播注冊與反注冊的方式,對兩個組件進行解耦纽帖。如果使用Handler傳遞到后臺線程作為回調(diào)宠漩,容易帶來的內(nèi)存泄漏。原因是:匿名內(nèi)部類對外面的Actvitiy持有引用懊直,如果在Acitivity被銷毀的時候扒吁,沒有對Handler進行顯式的解綁,會導(dǎo)致Activity無法正常銷毀室囊,這樣自然就有了內(nèi)存泄漏