本節(jié)前言
Android四大組件之一服務(wù)(Service)的簡單學(xué)習(xí)
Service的區(qū)別及分類
前臺(tái)服務(wù)和后臺(tái)服務(wù)最大的區(qū)別是:
1.前臺(tái)Service在下拉通知欄有顯示通知,但后臺(tái)Service沒有罪针。
2.前臺(tái)Service優(yōu)先級較高,不會(huì)由于系統(tǒng)內(nèi)存不足而被回收;后臺(tái)Service優(yōu)先級較低牛郑,當(dāng)系統(tǒng)
出現(xiàn)內(nèi)存不足情況時(shí)贬芥,很有可能會(huì)被回收摔桦。
有人可能會(huì)問,后臺(tái)服務(wù)我們可以自己創(chuàng)建 ONGOING 的 Notification 這樣就成為前臺(tái)服務(wù)嗎慨菱?答案是否定的,前臺(tái)服務(wù)是在做了上述工作之后需要調(diào)用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服務(wù)成為 前臺(tái)服務(wù)戴甩。這樣做的好處在于符喝,當(dāng)服務(wù)被外部強(qiáng)制終止掉的時(shí)候,ONGOING 的 Notification 任然會(huì)移除掉甜孤。
Service生命周期
第一種方式:通過StartService啟動(dòng)Service
通過startService啟動(dòng)后协饲,service會(huì)一直無限期運(yùn)行下去,只有外部調(diào)用了stopService()或stopSelf()方法時(shí)缴川,該Service才會(huì)停止運(yùn)行并銷毀茉稠。
要?jiǎng)?chuàng)建一個(gè)這樣的Service,你需要讓該類繼承Service類把夸,然后重寫以下方法:
onCreate()
1.如果service沒被創(chuàng)建過战惊,調(diào)用startService()后會(huì)執(zhí)行onCreate()回調(diào);
2.如果service已處于運(yùn)行中扎即,調(diào)用startService()不會(huì)執(zhí)行onCreate()方法吞获。
也就是說,onCreate()只會(huì)在第一次創(chuàng)建service時(shí)候調(diào)用谚鄙,多次執(zhí)行startService()不會(huì)重復(fù)調(diào)用onCreate()各拷,此方法適合完成一些初始化工作。
onStartCommand()
如果多次執(zhí)行了Context的startService()方法闷营,那么Service的onStartCommand()方法也會(huì)相應(yīng)的多次調(diào)用烤黍。onStartCommand()方法很重要,我們在該方法中根據(jù)傳入的Intent參數(shù)進(jìn)行實(shí)際的操作傻盟,比如會(huì)在此處創(chuàng)建一個(gè)線程用于下載數(shù)據(jù)或播放音樂等速蕊。
onBind()
Service中的onBind()方法是抽象方法,Service類本身就是抽象類娘赴,所以onBind()方法是必須重寫的规哲,即使我們用不到。
onDestory()
在銷毀的時(shí)候會(huì)執(zhí)行Service該方法诽表。
這幾個(gè)方法都是回調(diào)方法唉锌,且在主線程中執(zhí)行隅肥,由android操作系統(tǒng)在合適的時(shí)機(jī)調(diào)用。
第二種方式:通過bindService啟動(dòng)Service
bindService啟動(dòng)服務(wù)特點(diǎn):
1.bindService啟動(dòng)的服務(wù)和調(diào)用者之間是典型的client-server模式袄简。調(diào)用者是client腥放,service則是server端。service只有一個(gè)绿语,但綁定到service上面的client可以有一個(gè)或很多個(gè)秃症。這里所提到的client指的是組件,比如某個(gè)Activity吕粹。
2.client可以通過IBinder接口獲取Service實(shí)例种柑,從而實(shí)現(xiàn)在client端直接調(diào)用Service中的方法以實(shí)現(xiàn)靈活交互,這在通過startService方法啟動(dòng)中是無法實(shí)現(xiàn)的昂芜。
3.bindService啟動(dòng)服務(wù)的生命周期與其綁定的client息息相關(guān)莹规。當(dāng)client銷毀時(shí),client會(huì)自動(dòng)與Service解除綁定泌神。當(dāng)然良漱,client也可以明確調(diào)用Context的unbindService()方法與Service解除綁定。當(dāng)沒有任何client與Service綁定時(shí)欢际,Service會(huì)自行銷毀母市。
Android8.0后啟動(dòng)Service服務(wù)
Android在8.0開始限制后臺(tái)服務(wù),啟動(dòng)后臺(tái)服務(wù)需要設(shè)置通知欄损趋,使服務(wù)變成前臺(tái)服務(wù)患久。同時(shí)在Android 9.0開始注冊權(quán)限android.permission.FOREGROUND_SERVICE,并授權(quán)權(quán)限浑槽。
從8.0開始啟動(dòng)服務(wù)需要進(jìn)行判斷出來如下:
/**
* Android 8.0及以后,啟動(dòng)服務(wù)的形式已經(jīng)變了
*/
private void startService(Context context) {
Intent intent = new Intent(context, MyForegroundService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
}
同時(shí)在Service的onCreate()方法里設(shè)置通知欄如下:
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
NotificationManager notificationManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
//創(chuàng)建NotificationChannel
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel = new NotificationChannel(NOTIFICATION_ID,
NOTIFICATION_NAME, NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
}
//Android9.0會(huì)報(bào)Caused by: java.lang.SecurityException: Permission Denial:
//android.permission.FOREGROUND_SERVICE---AndroidManifest.xml中需要申請此權(quán)限
startForeground(1,getNotification());
}
//這個(gè)必須加蒋失,不能設(shè)置為null
private Notification getNotification() {
Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("測試服務(wù)")
.setContentText("我正在運(yùn)行");//標(biāo)題和內(nèi)容可以不加
//設(shè)置Notification的ChannelID,否則不能正常顯示
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(NOTIFICATION_ID);
}
Notification notification = builder.build();
return notification;
}
}
說明:
測試發(fā)現(xiàn)Android8.0后如果用startService啟動(dòng)服務(wù),應(yīng)用退到后臺(tái)后此服務(wù)一會(huì)兒就會(huì)被殺掉桐玻;如果用startForegroundService啟動(dòng)服務(wù)篙挽,并且添加了消息通知后,應(yīng)用后臺(tái)掛起則不會(huì)被系統(tǒng)殺掉