為什么要使用服務(wù)
service是Android中實(shí)現(xiàn)程序后臺(tái)運(yùn)行的解決方案,它非常適合執(zhí)行那些不需要和用戶交互而且還要求長(zhǎng)期運(yùn)行的任務(wù)高帖。
本篇對(duì)Service的基本使用進(jìn)行探討
- 使用Service需要注意的點(diǎn)
- Service的基本使用
- Service的更多用法探討稿饰,前臺(tái)服務(wù)杀赢、IntentService。
Service注意點(diǎn):
- Service不是運(yùn)行在單獨(dú)的進(jìn)程當(dāng)中的湘纵,而是依賴于創(chuàng)建服務(wù)時(shí)所在的應(yīng)用進(jìn)程脂崔。
- 當(dāng)依賴的進(jìn)程被殺掉時(shí),Service也會(huì)停止運(yùn)行梧喷。
- 服務(wù)不會(huì)自動(dòng)開啟線程砌左,所有的代碼默認(rèn)在主線程中運(yùn)行。
- 創(chuàng)建服務(wù)我們通常需要在服務(wù)內(nèi)部創(chuàng)建子線程铺敌,并在子線程中執(zhí)行具體任務(wù)汇歹,否則可能出現(xiàn)主線程阻塞的情況。
- 任何一個(gè)服務(wù)在整個(gè)應(yīng)用程序范圍內(nèi)都是通用的偿凭。多個(gè)活動(dòng)綁定同一個(gè)Service時(shí)产弹,所有活動(dòng)都能獲取到相同的DownloadBinder實(shí)例。
基本用法:
定義一個(gè)服務(wù):
Exported屬性表示是否允許除了當(dāng)前程序之外的其他程序訪問這個(gè)服務(wù)。Enable屬性表示是否啟用這個(gè)服務(wù)痰哨。
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
生命周期:
onCreate->onStartCommand->onDestroy**onCreate**:在服務(wù)創(chuàng)建時(shí)調(diào)用胶果,可完成初始化工作。
onStartCommand:在每次服務(wù)啟動(dòng)時(shí)調(diào)用斤斧。**onDestroy**:在服務(wù)銷毀時(shí)調(diào)用早抠,用來回收不再使用的資源。
注意點(diǎn):
- 調(diào)用bindService()來啟動(dòng)服務(wù)時(shí)撬讽,會(huì)回調(diào)Service的onBind()方法蕊连,onCreate()先于onBind()。
- 當(dāng)對(duì)一個(gè)服務(wù)調(diào)用了startService()和bindService方法游昼,這種情況銷毀服務(wù)需要同時(shí)調(diào)用stopService()和unbindService()甘苍,Service中的onDestroy()才會(huì)調(diào)用。
啟動(dòng)和停止服務(wù):
- 無綁定啟動(dòng):這種啟動(dòng)模式使activity和service沒有關(guān)系烘豌,活動(dòng)不知道服務(wù)做了什么事情载庭,只知道啟動(dòng)和調(diào)用。
//activity中調(diào)用
Intent startIntent = new Intent(context, ServiceName.class);
startService(startIntent);
Intent stopIntent = new Intent(context, ServiceName.class);
stopService(stopIntent);
//Service中調(diào)用該方法也可實(shí)現(xiàn)停止服務(wù)
stopSelf();
- 綁定啟動(dòng):為了讓activity和service的關(guān)系更緊密一些扇谣,例如activity指揮service去干什么昧捷。`
(1) 在Service類定義個(gè)內(nèi)部類繼承Bider闲昭,并新建一個(gè)實(shí)例罐寨,在onBind中返回
public class MyService extends Service {
private static String TAG = "MyService";
private DownloadBinder binder = new DownloadBinder();
public class DownloadBinder extends Binder{
public void startDownload(){
Log.d(TAG, "startDownload");
}
public void getDownloadProgress(){
Log.d(TAG, "progress");
}
public void cancelDownload(){
Log.d(TAG, "cancelDownload");
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
(2) 在activity中生命service的內(nèi)部Binder,并新建一個(gè)Connection序矩,在onServiceConnected中下轉(zhuǎn)為自定義的Binder鸯绿,并調(diào)用自己定義的方法。
MyService.DownloadBinder binder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
binder = (MyService.DownloadBinder) iBinder;
binder.startDownload();
binder.getDownloadProgress();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
(3) 綁定啟動(dòng)簸淀,解綁停止
//activity中瓶蝴,綁定啟動(dòng)
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
//解綁停止
unbindService(connection);
bindService()第三個(gè)參數(shù)為標(biāo)志位, BIND_AUTO_CREATE表示活動(dòng)和服務(wù)進(jìn)行綁定后自動(dòng)創(chuàng)建服務(wù)租幕。
更多用法探討:
1. 前臺(tái)服務(wù)
為什么使用前臺(tái)服務(wù)舷手?后臺(tái)服務(wù)的優(yōu)先級(jí)是比較低的,如果系統(tǒng)出現(xiàn)內(nèi)存不足的情況劲绪,就可能會(huì)回收后臺(tái)運(yùn)行的服務(wù)男窟。如果你希望服務(wù)一直運(yùn)行著,就可以考慮使用前臺(tái)服務(wù)贾富。
前臺(tái)服務(wù)會(huì)有一個(gè)正在運(yùn)行的圖標(biāo)在系統(tǒng)狀態(tài)欄顯示歉眷,方便傳遞信息給用戶。比如下載進(jìn)度颤枪。
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
//創(chuàng)建前臺(tái)服務(wù)
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setContentText("content text")
.setContentTitle("content title")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
}
}
與創(chuàng)建通知的方法類似汗捡,通過啟動(dòng)服務(wù)即可啟動(dòng)實(shí)現(xiàn)前臺(tái)服務(wù)。
2. IntentService
為什么使用IntentService畏纲?`
由上面我們知道扇住,服務(wù)中的代碼是直接運(yùn)行在主線程中的春缕,若處理一些很耗時(shí)的工作,就很容易引起線程阻塞台囱,進(jìn)而導(dǎo)致ARN(Application Not Responding)淡溯。我們可以通過創(chuàng)建子線程解決這個(gè)問題,但很多時(shí)候我們會(huì)選擇偷懶簿训,IntentService就可以做到這一點(diǎn)咱娶,可以創(chuàng)建一個(gè)異步且支持自動(dòng)停止的服務(wù)。
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//處理具體業(yè)務(wù)邏輯
//處理完Service的具體業(yè)務(wù)邏輯后會(huì)自動(dòng)調(diào)用Destory()銷毀服務(wù)
}
}
這里需要提供一個(gè)無參構(gòu)造函數(shù)强品,必須實(shí)現(xiàn)父類的有參構(gòu)造函數(shù)膘侮。在子類onHandleIntent()中處理一些具體邏輯,因?yàn)檫@個(gè)方法已經(jīng)是在子線程中運(yùn)行的了的榛。
參考`
《第一行代碼》