Android四大組件之Activity
Android四大組件之Service
Android四大組件之BroadcastReceiver
Android四大組件之ContentProvider
Service
Service(服務(wù))是一個(gè)可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而不使用用戶界面的應(yīng)用組件。服務(wù)可由其他應(yīng)用組件啟動(dòng),而且即使用戶切換到其他應(yīng)用,服務(wù)仍將在后臺(tái)繼續(xù)運(yùn)行。 此外,組件可以綁定到服務(wù),以與之進(jìn)行交互,甚至是執(zhí)行進(jìn)程間通信 (IPC)。 例如,服務(wù)可以處理網(wǎng)絡(luò)事務(wù)、播放音樂(lè),執(zhí)行文件 I/O 或與內(nèi)容提供程序交互,而所有這一切均可在后臺(tái)進(jìn)行。
一、創(chuàng)建Service
直接定義一個(gè)類(lèi),繼承自Service,和activity一樣,也要在AndroidManifest.xml中配置該Service。代碼如下:
public class MyService extends Service{
//綁定服務(wù)時(shí)才會(huì)調(diào)用,必須要實(shí)現(xiàn)的方法
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
AndroidManifest.xml中配置如下:
<application
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--這里需要注意的是,service的配置也是在application標(biāo)簽中-->
<service android:name=".MyService"/>
</application>
二、Service的兩種開(kāi)啟方式
1.startService() 啟動(dòng)服務(wù)。
開(kāi)啟服務(wù)后,服務(wù)就會(huì)長(zhǎng)期的后臺(tái)運(yùn)行,即使調(diào)用者退出了,服務(wù)仍然在后臺(tái)繼續(xù)運(yùn)行,服務(wù)和調(diào)用者沒(méi)有什么關(guān)系,調(diào)用者是不可以訪問(wèn)服務(wù)里面的方法。
2.bindService() 綁定服務(wù)。
服務(wù)開(kāi)啟后,生命周期與調(diào)用者相關(guān)聯(lián),調(diào)用者掛了,服務(wù)也會(huì)跟著掛掉,調(diào)用者和服務(wù)綁定在一起,調(diào)用者可以間接的調(diào)用到服務(wù)里面的方法。
三、Service的生命周期
接下來(lái)分別從兩種開(kāi)啟方式生命周期說(shuō)起,官方為我們提供了Service生命周期示意圖:
1.startService() 啟動(dòng)服務(wù)
下面我們通過(guò)代碼來(lái)分析需要重寫(xiě)的回調(diào)方法有哪些?
public class MyService extends Service{
// 綁定服務(wù)時(shí)才會(huì)調(diào)用,必須要實(shí)現(xiàn)的方法
@Override
public IBinder onBind(Intent intent) {
Log.e("TAG","-MyService---onBind()----");
return null;
}
//首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序,如果服務(wù)已在運(yùn)行,則不會(huì)調(diào)用此方法。該方法只被調(diào)用一次
@Override
public void onCreate() {
super.onCreate();
Log.e("MyService","-MyService---onCreate()----");
}
//每次通過(guò)startService()方法啟動(dòng)Service時(shí)都會(huì)被回調(diào)。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("MyService","-MyService---onStartCommand()---intent:"
+ intent.getStringExtra("data"+"--flags="+flags+"-----startId"+startId));
return super.onStartCommand(intent, flags, startId);
}
//服務(wù)銷(xiāo)毀時(shí)的回調(diào)
@Override
public void onDestroy() {
Log.e("MyService","-MyService---onDestroy()----");
super.onDestroy();
}
}
我們可以將Service看出一個(gè)沒(méi)有前臺(tái)界面的Activity,看看如何啟動(dòng)一個(gè)Service服務(wù)。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("TAG", "---MainActivity--onCreate-----");
//啟動(dòng)服務(wù)
findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MyService.class);
intent.putExtra("data", "測(cè)試傳遞數(shù)據(jù)");
//我們啟動(dòng)一個(gè)Activity的時(shí)候是startActivity();
//在這里我們是啟動(dòng)一個(gè)service
startService(intent);
}
});
//停止服務(wù)
findViewById(R.id.btn_stop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, MyService.class);
stopService(intent);
}
});
}
//生命周期方法
........
}
接下來(lái),我們看下運(yùn)行結(jié)果
TAG: ---MainActivity--onCreate-----
TAG: ---MainActivity--onStart-----
TAG: ---MainActivity--onResume-----
TAG: -MyService---onCreate()----
TAG: -MyService---onStartCommand()---intent=測(cè)試傳遞數(shù)據(jù)---flags=0-----startId=1
TAG: -MyService---onStartCommand()---intent=測(cè)試傳遞數(shù)據(jù)---flags=0-----startId=2
銷(xiāo)毀MainActivity
TAG: ---MainActivity--onPause-----
TAG: ---MainActivity--onStop-----
TAG: ---MainActivity--onDestroy-----
重新開(kāi)啟MainActivity
TAG: ---MainActivity--onCreate-----
TAG: ---MainActivity--onStart-----
TAG: ---MainActivity--onResume-----
銷(xiāo)毀service
TAG: -MyService---onDestroy()----
當(dāng)我們第一次啟動(dòng)服務(wù)時(shí)執(zhí)行onCreate()、onStartCommand方法,當(dāng)我們?cè)俅螁?dòng)服務(wù)的時(shí)候,是沒(méi)有執(zhí)行onCreate()方法的,只有當(dāng)Service沒(méi)有創(chuàng)建的時(shí)候才會(huì)回調(diào)這個(gè)方法,一旦Service被創(chuàng)建后再次startService啟動(dòng)Service也不會(huì)再次回調(diào)這個(gè)方法。當(dāng)MainActivity銷(xiāo)毀時(shí),我們發(fā)現(xiàn)MyService中并沒(méi)有執(zhí)行onDestroy(),只有當(dāng)我們?cè)俅螁?dòng)MainActivity,點(diǎn)擊了停止服務(wù)后,MyService服務(wù)才被銷(xiāo)毀了,即使調(diào)用者退出了,服務(wù)仍然在后臺(tái)繼續(xù)運(yùn)行。
關(guān)于這幾個(gè)方法的說(shuō)明如下:
-
onBind()
當(dāng)另一個(gè)組件想通過(guò)調(diào)用 bindService() 與服務(wù)綁定時(shí),系統(tǒng)將調(diào)用此方法。在此方法的實(shí)現(xiàn)中,必須返回 一個(gè)IBinder 接口的實(shí)現(xiàn)類(lèi),供客戶端用來(lái)與服務(wù)進(jìn)行通信。無(wú)論是啟動(dòng)狀態(tài)還是綁定狀態(tài),此方法必須重寫(xiě),但在啟動(dòng)狀態(tài)的情況下直接返回 null。 -
onCreate()
首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序(在調(diào)用 onStartCommand() 或onBind() 之前)。如果服務(wù)已在運(yùn)行,則不會(huì)調(diào)用此方法,該方法只調(diào)用一次 -
onStartCommand(Intent intent, int flags, int startId)
當(dāng)另一個(gè)組件(如 Activity)通過(guò)調(diào)用 startService() 請(qǐng)求啟動(dòng)服務(wù)時(shí),系統(tǒng)將調(diào)用此方法。一旦執(zhí)行此方法,服務(wù)即會(huì)啟動(dòng)并可在后臺(tái)無(wú)限期運(yùn)行。 如果自己實(shí)現(xiàn)此方法,則需要在服務(wù)工作完成后,通過(guò)調(diào)用 stopSelf() 或 stopService() 來(lái)停止服務(wù)。(在綁定狀態(tài)下,無(wú)需實(shí)現(xiàn)此方法。)
我們看下這三個(gè)參數(shù):
- intent :?jiǎn)?dòng)時(shí),啟動(dòng)組件傳遞過(guò)來(lái)的Intent,如Activity可利用Intent封裝所需要的參數(shù)并傳遞給Service
- flags:表示啟動(dòng)請(qǐng)求時(shí)是否有額外數(shù)據(jù)
可選值有0,START_FLAG_REDELIVERY,START_FLAG_RETRY。
0 代表沒(méi)有;
START_FLAG_REDELIVERY 這個(gè)值代表了onStartCommand方法的返回值為
START_REDELIVER_INTENT,而且在上一次服務(wù)被殺死前會(huì)去調(diào)用stopSelf方法停止服務(wù)。其中START_REDELIVER_INTENT意味著當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,則會(huì)重建服務(wù),并通過(guò)傳遞給服務(wù)的最后一個(gè) Intent 調(diào)用 onStartCommand(),此時(shí)Intent時(shí)有值的。
START_FLAG_RETRY該flag代表當(dāng)onStartCommand調(diào)用后一直沒(méi)有返回值時(shí),會(huì)嘗試重新去調(diào)用onStartCommand()。 - startId:指明當(dāng)前服務(wù)的唯一ID,與stopSelfResult (int startId)配合使用,stopSelfResult 可以更安全地根據(jù)ID停止服務(wù)。
實(shí)際上onStartCommand的返回值int類(lèi)型才是最最值得注意的,它有三種可選值, START_STICKY,START_NOT_STICKY,START_REDELIVER_INTENT,它們具體含義如下:
START_STICKY: 當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,一段時(shí)間后內(nèi)存再次空閑時(shí),系統(tǒng)將會(huì)嘗試重新創(chuàng)建此Service,一旦創(chuàng)建成功后將回調(diào)onStartCommand方法,但其中的Intent將是null,除非有掛起的Intent,如pendingintent,這個(gè)狀態(tài)下比較適用于不執(zhí)行命令、但無(wú)限期運(yùn)行并等待作業(yè)的媒體播放器或類(lèi)似服務(wù)。
START_NOT_STICKY: 當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,即使系統(tǒng)內(nèi)存再次空閑時(shí),系統(tǒng)也不會(huì)嘗試重新創(chuàng)建此Service。除非程序中再次調(diào)用startService啟動(dòng)此Service,這是最安全的選項(xiàng),可以避免在不必要時(shí)以及應(yīng)用能夠輕松重啟所有未完成的作業(yè)時(shí)運(yùn)行服務(wù)。
START_REDELIVER_INTENT:當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,則會(huì)重建服務(wù),并通過(guò)傳遞給服務(wù)的最后一個(gè) Intent 調(diào)用 onStartCommand(),任何掛起 Intent均依次傳遞。與START_STICKY不同的是,其中的傳遞的Intent將是非空,是最后一次調(diào)用startService中的intent。這個(gè)值適用于主動(dòng)執(zhí)行應(yīng)該立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)。
-
onDestroy()
當(dāng)服務(wù)不再使用且將被銷(xiāo)毀時(shí),系統(tǒng)將調(diào)用此方法。服務(wù)應(yīng)該實(shí)現(xiàn)此方法來(lái)清理所有資源,如線程、注冊(cè)的偵聽(tīng)器、接收器等,這是服務(wù)接收的最后一個(gè)調(diào)用。
由于每次啟動(dòng)服務(wù)(調(diào)用startService)時(shí),onStartCommand方法都會(huì)被調(diào)用,因此我們可以通過(guò)該方法使用Intent給Service傳遞所需要的參數(shù),然后在onStartCommand方法中處理的事件,最后根據(jù)需求選擇不同的Flag返回值,以達(dá)到對(duì)程序更友好的控制。
2.bindService() 綁定服務(wù)
前面了解了啟動(dòng)和停止服務(wù)的方法,雖然服務(wù)是在活動(dòng)(Activity)里啟動(dòng)的,但在啟動(dòng)了服務(wù)后,活動(dòng)與服務(wù)基本上就沒(méi)有什么關(guān)系了。我們調(diào)用了startService()方法來(lái)啟東MyService這個(gè)服務(wù),然后MyService的OnCreate()和onStartCommand()方法就會(huì)得到執(zhí)行,之后服務(wù)會(huì)一直處于運(yùn)行狀態(tài),但是具體運(yùn)行的是什么邏輯,活動(dòng)就控制不了了。那么我們?cè)撊绾卧诨顒?dòng)中去控制Service呢,這就需要借助onBind()方法了。
比如,我們希望在MyService里提供一個(gè)下載功能,然后在活動(dòng)中可以決定何時(shí)開(kāi)始下載,以及查看下載進(jìn)度,創(chuàng)建一個(gè)專(zhuān)門(mén)的Binder對(duì)象來(lái)對(duì)下載功能進(jìn)行模擬:
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
// 綁定服務(wù)時(shí)才會(huì)調(diào)用,必須要實(shí)現(xiàn)的方法
@Override
public IBinder onBind(Intent intent) {
Log.e("TAG", "-MyService---onBind()----");
return mBinder;
}
//首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序,如果服務(wù)已在運(yùn)行,則不會(huì)調(diào)用此方法。該方法只被調(diào)用一次
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG", "-MyService---onCreate()----");
}
//每次通過(guò)startService()方法啟動(dòng)Service時(shí)都會(huì)被回調(diào)。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("TAG", "-MyService---onStartCommand()---intent=" + intent.getStringExtra("data") + "---flags=" + flags + "-----startId=" + startId);
return super.onStartCommand(intent, flags, startId);
}
//服務(wù)銷(xiāo)毀時(shí)的回調(diào)
@Override
public void onDestroy() {
Log.e("TAG", "-MyService---onDestroy()----");
super.onDestroy();
}
class DownloadBinder extends Binder {
public void startDownload() {
Log.e("TAG", "開(kāi)始下載......");
}
public int getProgress() {
Log.e("TAG", "下載進(jìn)度......");
return 0;
}
}
}
在這里,我們創(chuàng)建一個(gè)DownloadBinder類(lèi),并繼承自Binder,然后在其內(nèi)部模擬開(kāi)始下和查看下載進(jìn)度的方法,分別打印下日志信息。在MyService中創(chuàng)建DownloadBinder 的實(shí)例,然后在onBind()方法中返回這個(gè)實(shí)例,這樣MyService中的工作就全部完成了。
接下來(lái)我們?cè)贛ainActivity中調(diào)用這個(gè)方法
public class MainActivity extends AppCompatActivity {
private MyService.DownloadBinder downloadBinder;
private ServiceConnection serviceConnection = new ServiceConnection() {
/**
* 系統(tǒng)會(huì)調(diào)用該方法以傳遞服務(wù)的 onBind() 方法返回的 IBinder。
* 其中service便是服務(wù)端返回的IBinder實(shí)現(xiàn)類(lèi)對(duì)象,
* 通過(guò)該對(duì)象我們便可以調(diào)用獲取LocalService實(shí)例對(duì)象,
* 進(jìn)而調(diào)用服務(wù)端的公共方法。
* 而ComponentName是一個(gè)封裝了組件(Activity, Service, BroadcastReceiver, or ContentProvider)信息的類(lèi),
* 如包名,組件描述等信息,較少使用該參數(shù)。
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
/**
* Android 系統(tǒng)會(huì)在與服務(wù)的連接意外中斷時(shí)(例如當(dāng)服務(wù)崩潰或被終止時(shí))調(diào)用該方法。
* 注意:當(dāng)客戶端取消綁定時(shí),系統(tǒng)“絕對(duì)不會(huì)”調(diào)用該方法。
*/
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("TAG", "---MainActivity--onCreate-----");
//綁定服務(wù)
findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
});
//解綁服務(wù)
findViewById(R.id.btn_stop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(serviceConnection);
}
});
}
}
我們看下運(yùn)行結(jié)果
TAG: -MyService---onCreate()----
-MyService---onBind()----
TAG: 開(kāi)始下載......
下載進(jìn)度......
TAG: -MyService---onDestroy()----
首先創(chuàng)建了一個(gè)ServiceConnection 的匿名類(lèi),在里面重寫(xiě)了onServiceConnected()方法和onServiceDisconnected()方法,這兩個(gè)方法分別會(huì)在活動(dòng)與服務(wù)成功綁定以及解除綁定的時(shí)候調(diào)用。在onServiceConnected()方法中,通過(guò)向下轉(zhuǎn)型得到了DownloadBinder實(shí)例,有了這個(gè)實(shí)例,我們就可以進(jìn)行操作服務(wù)了。
在這里我們可以看到也是需要Intent對(duì)象來(lái)實(shí)現(xiàn)的,和啟動(dòng)服務(wù)不一樣的是:啟動(dòng)服務(wù)時(shí) startService(),而綁定服務(wù)的時(shí)候是bindService(),bindService()方法接收3個(gè)參數(shù),第一個(gè)參數(shù)就是Intent對(duì)象,第二個(gè)參數(shù)就是ServiceConnection 的實(shí)例,第三個(gè)參數(shù)BIND_AUTO_CREATE 表示活動(dòng)和服務(wù)進(jìn)行綁定后自動(dòng)創(chuàng)建服務(wù)。這會(huì)使得MyService中的OnCreate()方法得到執(zhí)行,但是不會(huì)執(zhí)行onStartCommand()方法。
我們想要解除活動(dòng)和服務(wù)之間的綁定,就需要調(diào)用unbindService()方法,傳入當(dāng)前的ServiceConnection實(shí)例即可。
需要注意的是,任何一個(gè)服務(wù)在整個(gè)應(yīng)用程序范圍內(nèi)都是通用多的,MyService 可以和任何一個(gè)活動(dòng)進(jìn)行綁定,綁定完成后它們都可以獲取相同的DownloadBinder實(shí)例。
四、關(guān)于綁定服務(wù)的注意點(diǎn)
1.多個(gè)客戶端可同時(shí)連接到一個(gè)服務(wù)。不過(guò),只有在第一個(gè)客戶端綁定時(shí),系統(tǒng)才會(huì)調(diào)用服務(wù)的 onBind() 方法來(lái)檢索 IBinder。系統(tǒng)隨后無(wú)需再次調(diào)用 onBind(),便可將同一 IBinder 傳遞至任何其他綁定的客戶端。當(dāng)最后一個(gè)客戶端取消與服務(wù)的綁定時(shí),系統(tǒng)會(huì)將服務(wù)銷(xiāo)毀(除非 startService() 也啟動(dòng)了該服務(wù))。
2.通常情況下我們應(yīng)該在客戶端生命周期(如Activity的生命周期)的引入 和退出時(shí)刻設(shè)置綁定和取消綁定操作,以便控制綁定狀態(tài)下的Service,一般有以下兩種情況:
(1)如果只需要在 Activity 可見(jiàn)時(shí)與服務(wù)交互,則應(yīng)在 onStart() 期間綁定,在 onStop() 期間取消綁定。
(2)如果希望 Activity 在后臺(tái)停止運(yùn)行狀態(tài)下仍可接收響應(yīng),則可在 onCreate() 期間綁定,在 onDestroy() 期間取消綁定。需要注意的是,這意味著 Activity 在其整個(gè)運(yùn)行過(guò)程中(甚至包括后臺(tái)運(yùn)行期間)都需要使用服務(wù),因此如果服務(wù)位于其他進(jìn)程內(nèi),那么當(dāng)提高該進(jìn)程的權(quán)重時(shí),系統(tǒng)很可能會(huì)終止該進(jìn)程。
3.通常情況下(注意),切勿在 Activity 的 onResume() 和 onPause() 期間綁定和取消綁定,因?yàn)槊恳淮紊芷谵D(zhuǎn)換都會(huì)發(fā)生這些回調(diào),這樣反復(fù)綁定與解綁是不合理的。此外,如果應(yīng)用內(nèi)的多個(gè) Activity 綁定到同一服務(wù),并且其中兩個(gè) Activity 之間發(fā)生了轉(zhuǎn)換,則如果當(dāng)前 Activity 在下一次綁定(恢復(fù)期間)之前取消綁定(暫停期間),系統(tǒng)可能會(huì)銷(xiāo)毀服務(wù)并重建服務(wù),因此服務(wù)的綁定不應(yīng)該發(fā)生在 Activity 的 onResume() 和 onPause()中。
4.我們應(yīng)該始終捕獲 DeadObjectException DeadObjectException 異常,該異常是在連接中斷時(shí)引發(fā)的,表示調(diào)用的對(duì)象已死亡,也就是Service對(duì)象已銷(xiāo)毀,這是遠(yuǎn)程方法引發(fā)的唯一異常,DeadObjectException繼承自RemoteException,因此我們也可以捕獲RemoteException異常。
5.應(yīng)用組件(客戶端)可通過(guò)調(diào)用 bindService() 綁定到服務(wù),Android 系統(tǒng)隨后調(diào)用服務(wù)的 onBind() 方法,該方法返回用于與服務(wù)交互的 IBinder,而該綁定是異步執(zhí)行的。
IntentService
一、IntentService與Service的區(qū)別
IntentService是繼承并處理異步請(qǐng)求的一個(gè)類(lèi),在IntentService內(nèi)有一個(gè)工作線程來(lái)處理耗時(shí)操作,啟動(dòng)IntentService的方式和啟動(dòng)傳統(tǒng)的Service一樣,同時(shí),當(dāng)任務(wù)執(zhí)行完后,IntentService會(huì)自動(dòng)停止,而不需要我們手動(dòng)去控制或stopSelf()。另外,可以啟動(dòng)IntentService多次,而每一個(gè)耗時(shí)操作會(huì)以工作隊(duì)列的方式在IntentService的onHandleIntent回調(diào)方法中執(zhí)行,并且,每次只會(huì)執(zhí)行一個(gè)工作線程,執(zhí)行完第一個(gè)再執(zhí)行第二個(gè),以此類(lèi)推。
IntentService的源碼
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
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);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* <p>If enabled is true,
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before
* {@link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
* <p>If enabled is false (the default),
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@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);
}
@Override
public void onStart(@Nullable 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(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
IntentService繼承自Service,內(nèi)部有一個(gè)HandlerThread對(duì)象。
????在onCreate的時(shí)候會(huì)創(chuàng)建一個(gè)HandlerThread對(duì)象,并啟動(dòng)線程。緊接著創(chuàng)建ServiceHandler對(duì)象,ServiceHandler繼承自Handler,用來(lái)處理消息。ServiceHandler將獲取HandlerThread的Looper就可以開(kāi)始正常工作了。
????每啟動(dòng)一次onStart方法,就會(huì)把數(shù)消息和數(shù)據(jù)發(fā)給mServiceHandler,相當(dāng)于發(fā)送了一次Message消息給HandlerThread的消息隊(duì)列。mServiceHandler會(huì)把數(shù)據(jù)傳個(gè)onHandleIntent方法,onHandleIntent是個(gè)抽象方法,需要在IntentService實(shí)現(xiàn),所以每次onStart方法之后都會(huì)調(diào)用我們自己寫(xiě)的onHandleIntent方法去處理。處理完畢使用stopSelf通知HandlerThread已經(jīng)處理完畢,HandlerThread繼續(xù)觀察消息隊(duì)列,如果還有未執(zhí)行玩的message則繼續(xù)執(zhí)行,否則結(jié)束。
IntentService的實(shí)現(xiàn):
public class MyIntentService extends IntentService{
/**
* 無(wú)參構(gòu)造方法 一定要實(shí)現(xiàn)此方法否則Service運(yùn)行出錯(cuò)。
*
* 錯(cuò)誤如下java.lang.RuntimeException: Unable to instantiate service com.monkey.servicedemo.MyIntentService:
* java.lang.InstantiationException: java.lang.Class<com.monkey.servicedemo.MyIntentService> has no zero argument constructor
*/
public MyIntentService() {
super("MyIntentService");
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.e("MyIntentService--", "onHandleIntent()");
//耗時(shí)操作
for(int i = 0; i < 3; i++){
Log.e("onHandleIntent--", i + "--" + Thread.currentThread().getName());
}
}
@Override
public void onCreate() {
super.onCreate();
Log.e("MyIntentService--", "onCreate()");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e("MyIntentService--", "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e("MyIntentService--", "onDestroy()");
super.onDestroy();
}
}
啟動(dòng)IntentService
//啟動(dòng)前一定不要忘記注冊(cè)
<service android:name=".MyIntentService"/>
Intent intent = new Intent(MainActivity.this, MyIntentService.class);
startService(intent);
運(yùn)行結(jié)果
E/MyIntentService--: onCreate()
E/MyIntentService--: onStartCommand()
E/MyIntentService--: onHandleIntent()
E/onHandleIntent--: 0--IntentService[MyIntentService]
1--IntentService[MyIntentService]
2--IntentService[MyIntentService]
E/MyIntentService--: onDestroy()
IntentService開(kāi)啟后,執(zhí)行完onHandleIntent里面的任務(wù)就自動(dòng)銷(xiāo)毀結(jié)束,并不需要我們?nèi)ブ鲃?dòng)的關(guān)閉。
總結(jié):
1、啟動(dòng) IntentService 是不需要新建線程。IntentService內(nèi)部的HandlerThread 繼承自 Thread,內(nèi)部封裝了 Looper,在這里新建線程并啟動(dòng),所以啟動(dòng) IntentService 不需要新建線程。
2、不建議通過(guò) bindService() 啟動(dòng) IntentService。IntentService 源碼中的 onBind() 默認(rèn)返回 null;不適合 bindService() 啟動(dòng)服務(wù),如果你執(zhí)意要 bindService() 來(lái)啟動(dòng) IntentService,可能因?yàn)槟阆胪ㄟ^(guò) Binder 或 Messenger 使得 IntentService 和 Activity 可以通信,這樣那么 onHandleIntent() 不會(huì)被回調(diào),相當(dāng)于在你使用 Service 而不是 IntentService。
3、多次啟動(dòng) IntentService 會(huì)順序執(zhí)行事件,停止服務(wù)后,后續(xù)的事件得不到執(zhí)行。IntentService 中使用的 Handler、Looper、MessageQueue 機(jī)制把消息發(fā)送到線程中去執(zhí)行的,所以多次啟動(dòng) IntentService 不會(huì)重新創(chuàng)建新的服務(wù)和新的線程,只是把消息加入消息隊(duì)列中等待執(zhí)行,而如果服務(wù)停止,會(huì)清除消息隊(duì)列中的消息,后續(xù)的事件得不到執(zhí)行。