Service是一種可以在后臺(tái)執(zhí)行耗時(shí)操作而沒有用戶界面的應(yīng)用組件锚烦。它默認(rèn)運(yùn)行在主線程中邦投,不可以直接進(jìn)行耗時(shí)操作,關(guān)于在Service中進(jìn)行耗時(shí)操作詳見本文末尾 —— IntentService膨更。
Android四大組件中只有Activity和Service是Context的子類
如果用戶在應(yīng)用管理界面手動(dòng)停止了Service所在進(jìn)程挺邀,Service就會(huì)停止;如果是內(nèi)存不足導(dǎo)致Android系統(tǒng)殺死了Service所在進(jìn)程灯萍,Service也會(huì)停止轧铁,只是當(dāng)內(nèi)存充足時(shí)系統(tǒng)又會(huì)重啟該Service所在進(jìn)程(服務(wù)進(jìn)程),Service也會(huì)被重新啟動(dòng)旦棉。
Android進(jìn)程優(yōu)先級(jí)
-
前臺(tái)進(jìn)程(Foreground process):優(yōu)先級(jí)最高齿风,最重要并且最后一個(gè)被Android系統(tǒng)殺死药薯。滿足下面任意一條的進(jìn)程就是前臺(tái)進(jìn)程
- 擁有一個(gè)正在與用戶交互的Activity(onResume()被調(diào)用)
- 擁有一個(gè)與其他進(jìn)程中正在與用戶交互的Activity綁定的Service
- 擁有一個(gè)正在執(zhí)行onCreate()、onStartCommand()救斑、onDestroy()其中一個(gè)生命周期方法的Service(Service在執(zhí)行生命周期方法時(shí)童本,短暫提高其所在進(jìn)程的優(yōu)先級(jí),以保證進(jìn)程不會(huì)被系統(tǒng)殺死)
- 擁有一個(gè)正在執(zhí)行onReceive()的BroadcastReceiver(BroadcastReceiver在收到廣播時(shí)脸候,短暫提高其所在進(jìn)程的優(yōu)先級(jí)穷娱,以保證進(jìn)程不會(huì)被系統(tǒng)殺死)
-
可見進(jìn)程(Visible process):滿足下面任意一條的進(jìn)程就是可見進(jìn)程
- 擁有一個(gè)不在前臺(tái)(失去焦點(diǎn))但是對(duì)用戶依然可見的Activity(onPause()被調(diào)用)
- 擁有一個(gè)與其他進(jìn)程中可見Activity綁定的Service
- 擁有一個(gè)調(diào)用了
service.startForeground(id, notification)
運(yùn)行在前臺(tái)的Service
服務(wù)進(jìn)程(Service process):擁有一個(gè)通過
content.startService(intent)
啟動(dòng)的Service,不到萬不得已時(shí)不會(huì)被Android系統(tǒng)殺死运沦。即使在內(nèi)存不足時(shí)被系統(tǒng)殺死了鄙煤,等到內(nèi)存充足時(shí)仍然可以被重新啟動(dòng),繼續(xù)運(yùn)行該Service茶袒。只有服務(wù)進(jìn)程才可以用來做文件下載梯刚、音樂播放等后臺(tái)操作后臺(tái)進(jìn)程(Background process):擁有一個(gè)用戶不可見的Activity(onStop()被調(diào)用),很容易被Android系統(tǒng)殺死薪寓,且不會(huì)被重新啟動(dòng)
空進(jìn)程(Empty process):不含有任何活動(dòng)的應(yīng)用組件(主要是Activity和Service亡资,BroadcastReceiver的生命周期很短),保留空進(jìn)程的唯一目的就是作為緩存向叉,以加快下次在此進(jìn)程中運(yùn)行組件的啟動(dòng)速度锥腻,優(yōu)先級(jí)最低,最容易被Android系統(tǒng)殺死母谎,且不會(huì)被重新啟動(dòng)
對(duì)于優(yōu)先級(jí)相同的進(jìn)程瘦黑,當(dāng)內(nèi)存不足時(shí),Android系統(tǒng)會(huì)依據(jù)LRU算法決定殺死哪一個(gè)進(jìn)程
Service的定義
創(chuàng)建一個(gè)類XxxService繼承Service奇唤,并重寫onBind()
public class XxxService extends Service {
/**
* bindService時(shí)才會(huì)回調(diào)幸斥,必須實(shí)現(xiàn)的方法
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
在清單文件中配置該Service
<service android:name=".XxxService"></service>
Service的兩種啟動(dòng)方式
從Android 5.0開始,Google要求必須使用顯式Intent啟動(dòng)Service
在Android系統(tǒng)中啟動(dòng)Service有如下兩種方式:
1. startService
通過content.startService(intent)
啟動(dòng)Service咬扇,將觸發(fā)Service的生命周期方法:onCreate() —> onStartCommand()
因?yàn)镾ervice沒有前臺(tái)界面所以Google使用onStartCommand()替代onStart()甲葬,它有一個(gè)int類型的返回值,如果返回START_STICKY懈贺,意味著如果Service所在進(jìn)程因?yàn)橄到y(tǒng)內(nèi)存不足而被殺掉经窖,當(dāng)內(nèi)存充足時(shí)系統(tǒng)還會(huì)嘗試重新創(chuàng)建這個(gè)Service,重新創(chuàng)建Service又會(huì)回調(diào)onStartCommand()梭灿,但這次傳入onStartCommand()中的Intent將為null
Intent intent = new Intent(this, XxxService.class);
startService(intent);
重復(fù)的startService()不會(huì)回調(diào)onCreate()画侣,只會(huì)回調(diào)onStartCommand()
不再使用時(shí),可以通過service.stopSelf()
或 context.stopService(intent)
停止Service堡妒,將觸發(fā)Service的生命周期方法:onDestroy()
Intent intent = new Intent(this, XxxService.class);
stopService(intent);
通過startService()啟動(dòng)的Service與啟動(dòng)它的Activity沒有任何關(guān)系配乱,即使Activity被銷毀了,Service也不會(huì)停止。另外宪卿,通過這種方式啟動(dòng)Service,該Service所在進(jìn)程的優(yōu)先級(jí)將不會(huì)低于服務(wù)進(jìn)程万栅。
2. bindService
通過content.bindService(intent, conn, flags)
啟動(dòng)Service佑钾,需要定義ServiceConnection接口的實(shí)現(xiàn)類
public class XxxConnection implements ServiceConnection {
/**
* 當(dāng)?shù)絊ervice的連接被建立了(Service的onBind()執(zhí)行成功)
* 并返回了一個(gè)非空的IBinder對(duì)象,此方法才會(huì)回調(diào)
*
* @param name
* @param service 這個(gè)對(duì)象就是onBind()返回的中間人IBinder
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
/**
* 當(dāng)?shù)絊ervice的連接因?yàn)楫惓6袛喾沉#朔椒ú艜?huì)回調(diào)休溶,正常的解綁不會(huì)回調(diào)此方法
*
* @param name
*/
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
然后創(chuàng)建該實(shí)現(xiàn)類的對(duì)象
XxxConnection conn = new XxxConnection();
通過bindService啟動(dòng)(綁定)Service,將觸發(fā)Service的生命周期方法:onCreate() —> onBind()
Intent intent = new Intent(this, XxxService.class);
bindService(intent, conn, BIND_AUTO_CREATE); // BIND_AUTO_CREATE表示如果XxxService不存在則自動(dòng)創(chuàng)建它
重復(fù)的bindService不會(huì)回調(diào)onCreate()和onBind().
通過context.unbindService(conn)
停止(解綁)Service將觸法生命周期方法:onUnbind() —> onDestroy()
unbindService(conn);
通常不推薦使用ApplicationContext去bindService扰她,如果通過這種方式bind了一個(gè)Local Service兽掰,此后每次start Remote Service都會(huì)拋出異常:android.os.BinderProxy cannot be cast to XxxService$XxxServiceBinder
如果Service想要同整個(gè)應(yīng)用的生命周期一致,可與MainActivity進(jìn)行bind
通過bindService()啟動(dòng)Service徒役,也叫綁定(多個(gè)Activity可以綁定一個(gè)Service)孽尽,它使Service與啟動(dòng)它的Activity建立連接:如果Activity被銷毀了,Service也會(huì)被解綁并銷毀忧勿;但是如果Service被銷毀了杉女,Activity則不會(huì)被銷毀。另外鸳吸,通過這種方式啟動(dòng)(綁定)Service熏挎,該Service所在的進(jìn)程優(yōu)先級(jí)不變(仍取決于啟動(dòng)服務(wù)的Activity)。
startService的應(yīng)用:后臺(tái)操作
Android系統(tǒng)通話有三種狀態(tài):空閑晌砾、響鈴坎拐、摘機(jī),我們可以在摘機(jī)時(shí)通過Service進(jìn)行后臺(tái)錄音來實(shí)現(xiàn)通話錄音機(jī)养匈。
定義一個(gè)RecorderService讓其在創(chuàng)建時(shí)就開始監(jiān)聽電話狀態(tài)
public class RecorderService extends Service {
@Override
public void onCreate() {
super.onCreate();
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); // 獲取電話管理器
tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE); // 監(jiān)聽電話狀態(tài)
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
自定義電話狀態(tài)監(jiān)聽器哼勇,當(dāng)響鈴時(shí)進(jìn)行音頻錄制的初始化(申請(qǐng)硬件資源),摘機(jī)時(shí)開始錄制呕乎,空閑時(shí)回收音頻錄制所占用的資源
class MyListener extends PhoneStateListener {
/**
* 電話狀態(tài)改變時(shí)回調(diào)
*
* @param state
* @param incomingNumber
*/
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) { // 判斷當(dāng)前是什么狀態(tài)
case TelephonyManager.CALL_STATE_IDLE: // 空閑
if (mediaRecorder != null) {
mediaRecorder.stop(); // 停止錄制音頻
mediaRecorder.release(); // 釋放錄音所占用的硬件資源(C代碼所占用的)
mediaRecorder = null; // 等待垃圾回收器回收java對(duì)象資源
}
break;
case TelephonyManager.CALL_STATE_RINGING: // 響鈴猴蹂,進(jìn)行音頻錄制的初始化
if (mediaRecorder == null) {
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 設(shè)置音頻源為麥克風(fēng)
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);// 設(shè)置所錄制的音頻文件格式為3gp
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 設(shè)置所錄制音頻的編碼格式AMR_NB(3gp文件格式的一種最常見的音頻編碼格式)
mediaRecorder.setOutputFile("sdcard/voice.3gp");// 設(shè)置所錄制的音頻文件的保存位置
try {
mediaRecorder.prepare();// 準(zhǔn)備錄制音頻
} catch (IOException e) {
e.printStackTrace();
}
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK: // 摘機(jī)
if (mediaRecorder == null) {
mediaRecorder.start(); // 開始錄制音頻
}
break;
}
}
}
注意不要忘了在清單文件中配置RecorderService以及申請(qǐng)所需要的權(quán)限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/> <!-- 讀取通話狀態(tài)權(quán)限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/> <!-- 錄制音頻權(quán)限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 寫SD卡權(quán)限 -->
<service android:name=".RecorderService"></service> <!-- 配置RecorderService -->
bindService的應(yīng)用:調(diào)用Service中的方法
在應(yīng)用中啟動(dòng)Service,系統(tǒng)會(huì)自動(dòng)為我們創(chuàng)建這個(gè)Service對(duì)象楣嘁,但是我們無法直接拿到這個(gè)Service對(duì)象的引用磅轻,也就無法在前臺(tái)調(diào)用這個(gè)Service中的非靜態(tài)方法。
想要找人辦個(gè)證逐虚,但不認(rèn)識(shí)領(lǐng)導(dǎo)聋溜,需要通過中間人馮秘書牽線!
把Service看成一個(gè)領(lǐng)導(dǎo)叭爱,服務(wù)中有一個(gè)banZheng()
撮躁,用bindService()
綁定Service時(shí),會(huì)觸發(fā)Service的onBind()
买雾,此方法會(huì)返回一個(gè)中間人Ibinder對(duì)象把曼,前臺(tái)可以在bindService()
時(shí)傳入的ServiceConnection實(shí)現(xiàn)類對(duì)象的onServiceConnected()
中拿到這個(gè)Ibinder對(duì)象杨帽,通過這個(gè)對(duì)象就可以訪問Service中的banZheng()
。
定義一個(gè)服務(wù)LeaderService嗤军,在服務(wù)中定義一個(gè)FengMiShu繼承Binder(實(shí)現(xiàn)了Ibinder接口)作為中間人注盈,以在onBind()中返回該類對(duì)象。
public class LeaderService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new FengMiShu(); // 返回中間人IBinder對(duì)象
}
/**
* 辦證
*/
public void banzheng() {
System.out.println("成功辦證");
}
/**
* 馮秘書(中間人)
*/
class FengMiShu extends Binder implements PublicBusiness {
/**
* 中間人的牽線
*/
@Override
public void qianXian() {
banzheng(); // 調(diào)用領(lǐng)導(dǎo)的辦證
}
/**
* 沒有抽象到接口中叙赚,不能隨便調(diào)用(撿肥皂不是對(duì)公業(yè)務(wù))
*/
public void jianFeiZao() {
}
}
}
把qianXian()
抽象到PublicBusiness接口中
public interface PublicBusiness {
void qianXian(); // 把需要被Activity調(diào)用的方法抽象到接口中(牽線屬于對(duì)公業(yè)務(wù))
}
在Activity中綁定服務(wù)時(shí)傳入一個(gè)ServiceConnection實(shí)現(xiàn)類的對(duì)象老客,如果不考慮解綁服務(wù)可直接用匿名內(nèi)部類定義
Intent intent = new Intent(this, LeaderService.class);
bindService(intent, new ServiceConnection() {
/**
* 到Service的連接被建立了(Service的onBind()執(zhí)行成功),并返回了一個(gè)非空的IBinder對(duì)象震叮,此方法才會(huì)回調(diào)
*
* @param name
* @param service 這個(gè)對(duì)象就是onBind()返回的中間人IBinder
*/
@Override
public void onServiceConnected (ComponentName name, IBinder service){
publicBusiness = (PublicBusiness) service; // 拿到中間人馮秘書胧砰,強(qiáng)轉(zhuǎn)成PublicBusiness使其只能調(diào)用對(duì)公業(yè)務(wù)
}
/**
* 到Service的連接因?yàn)楫惓6袛啵朔椒ú艜?huì)回調(diào)苇瓣,正常的解綁不會(huì)回調(diào)此方法
*
* @param name
*/
@Override
public void onServiceDisconnected (ComponentName name){
}
},BIND_AUTO_CREATE);
最后在Activity需要調(diào)用LeaderService的banzheng()
處調(diào)用以下代碼
publicBusiness.qianXian(); // 馮秘書的對(duì)公業(yè)務(wù)牽線
// publicBusiness.jianFeiZao(); // 非對(duì)公業(yè)務(wù)尉间,調(diào)用不了
Service的混合啟動(dòng):音樂播放器
實(shí)現(xiàn)音樂播放時(shí),要保證在Activity銷毀后音樂仍在后臺(tái)播放击罪,進(jìn)程不會(huì)變成空進(jìn)程而在內(nèi)存不足時(shí)被系統(tǒng)殺死乌妒,必須要通過startService()
把進(jìn)程變成服務(wù)進(jìn)程⊥獾耍可是音樂Service中的方法撤蚊,需要被前臺(tái)Activity所調(diào)用(例如當(dāng)用戶點(diǎn)擊開始或暫停按鈕要分別觸發(fā)Service中的播放音樂和暫停音樂),又必須要用bindService()
綁定服務(wù)损话,獲取Binder對(duì)象侦啸。所以需要用到上述兩種方式混合啟動(dòng)音樂Service,并且startService()必須在bindService()之前執(zhí)行丧枪。詳見多媒體編程:二光涂、音頻播放
混合啟動(dòng)服務(wù)時(shí)先startService(),再bindService()拧烦;停止服務(wù)時(shí)先unbindService()忘闻,再stopService()
Local Service 與 Remote Service
對(duì)于Web開發(fā),Local Service是指提供服務(wù)的程序在本地恋博,而Remote Service是指提供服務(wù)的程序在服務(wù)器
對(duì)于Android開發(fā)齐佳,Local Service和Remote Service都運(yùn)行在我們的手機(jī)上
Local Service
Local Service是指與啟動(dòng)它的組件都在同一進(jìn)程的Service,前面啟動(dòng)的Service均是Local Service.
Remote Service
Remote Service是指與啟動(dòng)它的組件不在同一進(jìn)程的Service债沮,它分為兩種:
-
同一應(yīng)用中的Remote Service:在清單文件中明確指定了Service所在的進(jìn)程炼吴,對(duì)于該應(yīng)用中位于不同進(jìn)程的其它組件,該Service就是一個(gè)Remote Service
<service android:name=".RemoteService" android:process=":newProcess" />
-
不同應(yīng)用中的Remote Service:在清單文件中配置了intent-filter子節(jié)點(diǎn)(此時(shí)
android:exported="true"
)疫衩,并指定action硅蹦,對(duì)于其他應(yīng)用(一般位于不同進(jìn)程,特例Android中如何設(shè)置兩個(gè)應(yīng)用程序?yàn)橥粋€(gè)進(jìn)程?)中的組件童芹,該Service就是一個(gè)Remote Service<service android:name=".RemoteService"> <intent-filter> <action android:name="a.b.c" /> </intent-filter> </service>
從Android 5.0以后涮瞻,開發(fā)者只能顯式的(指定包名)跨應(yīng)用啟動(dòng)Remote Service,下面是通過startService的方式跨應(yīng)用啟動(dòng)Remote Service的代碼:
Intent intent = new Intent(); intent.setPackage("edu.neu.steve.remoteservice");// Android 5.0之 后必須指明遠(yuǎn)程Service所在的應(yīng)用包名 intent.setAction("a.b.c"); // 與遠(yuǎn)程Service注冊(cè)時(shí)的action匹配 startService(intent);
AIDL
AIDL(Android Interface Defination Language)即Android接口定義語言假褪,用于Android進(jìn)程間通信署咽。
下面使用AIDL實(shí)現(xiàn)在Client端Bind Server端的Remote Service,從而調(diào)用Server端提供的遠(yuǎn)程服務(wù)嗜价,這里假設(shè)Client和Server不在同一應(yīng)用中。
Server端
- 在java目錄上右鍵幕庐,創(chuàng)建一個(gè)AIDL文件PublicBusiness.aidl久锥,并在其中聲明中間人的對(duì)公業(yè)務(wù)
qianXian()
,然后Make一下异剥,會(huì)自動(dòng)生成一個(gè)PublicBusiness.java(位于app/build/generated/source/aidl/debug下)
interface PublicBusiness {
void qianXian();
}
aidl接口中所有成員都是public的瑟由,不需要也不能自己設(shè)置訪問修飾符
- 在RemoteService內(nèi)定義中間人FengMiShu直接繼承抽象類PublicBusiness.Stub(查看生成的PublicBusiness.java源碼可知,這個(gè)內(nèi)部類Stub繼承自Binder并實(shí)現(xiàn)了PublicBusiness接口)冤寿,實(shí)現(xiàn)對(duì)公業(yè)務(wù)
qianXian()
歹苦,然后在onBind()
中返回FengMiShu的實(shí)例。RemoteService在清單文件中的配置同上
public class RemoteService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new FengMiShu(); // 返回中間人的實(shí)例
}
public void remoteBanzheng() {
System.out.println("領(lǐng)導(dǎo)在國外遠(yuǎn)程辦證");
}
/**
* 中間人馮秘書直接繼承Stub并實(shí)現(xiàn)qianXian()
*/
class FengMiShu extends PublicBusiness.Stub {
@Override
public void qianXian() {
remoteBanzheng();
}
}
}
Client端
由于Client和Server不在同一應(yīng)用中督怜,需要把Server端的PublicBusiness.aidl文件復(fù)制一份放到Client端殴瘦,保持該AIDL文件所在包名與Server端的AIDL文件所在包名一致。(如果Client和Server在同一應(yīng)用中号杠,則跳過該步)
在客戶端bind RemoteService蚪腋,綁定成功后使用
PublicBusiness.Stub.asInterface()
將從onServiceConnected()
中獲取到的中間人IBinder對(duì)象強(qiáng)轉(zhuǎn)成PublicBusiness類型(不同進(jìn)程中實(shí)際上返回的是一個(gè)代理),在需要時(shí)調(diào)用這個(gè)PublicBusiness對(duì)象的qianXian()
即可實(shí)現(xiàn)遠(yuǎn)程辦證
public class MainActivity extends AppCompatActivity {
public PublicBusiness publicBusiness;
private MyConnection myConn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myConn = new MyConnection();
}
class MyConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
publicBusiness = PublicBusiness.Stub.asInterface(service); // 強(qiáng)轉(zhuǎn)成PublicBusiness
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
/**
* 綁定服務(wù)
*
* @param v
*/
public void bind(View v) {
Intent intent = new Intent();
intent.setPackage("edu.neu.steve.remoteservice");
intent.setAction("a.b.c");
bindService(intent, myConn, BIND_AUTO_CREATE);
}
/**
* 解綁服務(wù)
*
* @param v
*/
public void unbind(View v) {
unbindService(myConn);
}
/**
* 在Activity中辦證
*
* @param v
*/
public void banZheng(View v) {
try {
publicBusiness.qianXian(); // 中間人前線姨蟋,領(lǐng)導(dǎo)在國外遠(yuǎn)程辦證
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
IntentService
在Android開發(fā)中屉凯,我們一般需要在Service中開啟一個(gè)子線程來執(zhí)行類似下載這樣的后臺(tái)耗時(shí)操作,因?yàn)锳ctivity可能會(huì)被用戶退出眼溶,而BroadcastReceiver的生命周期本身就很短悠砚,在Service中開啟子線程進(jìn)行耗時(shí)操作可以避免應(yīng)用進(jìn)程變?yōu)榭者M(jìn)程在內(nèi)存不足時(shí)被系統(tǒng)殺死。如果仍然擔(dān)心Service所在進(jìn)程被殺堂飞,還可以通過調(diào)用service.startForeground(id, notification)
提升應(yīng)用進(jìn)程的優(yōu)先級(jí)灌旧,這是一種比較常見的進(jìn)程保活方式绰筛。
然而自己去管理Service的生命周期以及子線程并非是個(gè)優(yōu)雅的做法节榜,好在Android給我們提供了IntentService,IntentService是Service的子類别智,用來處理異步請(qǐng)求宗苍,在IntentService內(nèi)有一個(gè)worker線程來處理耗時(shí)操作。使用IntentService,我們不需要在Service中自己去開啟一個(gè)子線程讳窟,也不需要考慮在什么時(shí)候停止Service.
擴(kuò)展IntentService實(shí)現(xiàn)Service無須重寫onBind()
让歼、onStartCommand()
,只需要重寫onHandleIntent()
public class MyIntentService extends IntentService {
/**
* IntentService的構(gòu)造函數(shù)一定是參數(shù)為空的構(gòu)造函數(shù)
* 然后再在其中調(diào)用super("name")這種形式的構(gòu)造函數(shù)
* 因?yàn)镮ntentService的實(shí)例化是系統(tǒng)用參數(shù)為空的構(gòu)造函數(shù)來完成的
*/
public MyIntentService() {
super("MyIntentService");
}
/**
* IntentService會(huì)使用單獨(dú)的線程來執(zhí)行該方法內(nèi)的代碼
* 該方法內(nèi)可以執(zhí)行任何耗時(shí)任務(wù)丽啡,比如下載文件等谋右,此處讓線程暫停20秒來模擬耗時(shí)操作
*
* @param intent
*/
@Override
protected void onHandleIntent(Intent intent) {
long endTime = System.currentTimeMillis() + 20 * 1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
System.out.println("---耗時(shí)任務(wù)執(zhí)行完成---");
}
}
不要忘了在清單文件中配置IntentService,因?yàn)樗^承于Service补箍,所以它仍是一個(gè)Service
<service android:name=".MyIntentService"></service>
客戶端可以通過startService(Intent)
方法傳遞請(qǐng)求給IntentService
Intent intent = new Intent(this, MyIntentService.class);// 創(chuàng)建需要啟動(dòng)的IntentService的Intent
startService(intent); // 啟動(dòng)IntentService
IntentService會(huì)將該Intent加入到隊(duì)列中改执,然后開啟一條新的worker線程來處理該Intent以及onHandleIntent()
中的耗時(shí)操作,不會(huì)阻塞主線程坑雅。
對(duì)于異步的startService()請(qǐng)求辈挂,IntentService會(huì)按次序依次處理隊(duì)列中的Intent,worker線程保證同一時(shí)刻只處理一個(gè)Intent裹粤。當(dāng)所有請(qǐng)求處理完成后终蒂,IntentService會(huì)自動(dòng)停止。