原文章轉(zhuǎn)載:http://blog.csdn.net/qq_30379689/article/details/53318861
前言
作為四大組件之一的Service類,是面試和筆試的必備關(guān)卡,我把我所學(xué)到的東西總結(jié)了一遍,相信你看了之后你會(huì)對Service娓娓道來,在以后遇到Service的問題胸有成竹,廢話不多說,開車?yán)?/p>
Service簡介
Service是Android中實(shí)現(xiàn)程序后臺運(yùn)行的解決方案,它非常適用于去執(zhí)行那些不需要和用戶交互而且還要求長期運(yùn)行的任務(wù)。Service默認(rèn)并不會(huì)運(yùn)行在子線程中,它也不運(yùn)行在一個(gè)獨(dú)立的進(jìn)程中,它同樣執(zhí)行在UI線程中,因此,不要在Service中執(zhí)行耗時(shí)的操作,除非你在Service中創(chuàng)建了子線程來完成耗時(shí)操作
Service的運(yùn)行不依賴于任何用戶界面,即使程序被切換到后臺或者用戶打開另一個(gè)應(yīng)用程序,Service仍然能夠保持正常運(yùn)行,這也正是Service的使用場景。當(dāng)某個(gè)應(yīng)用程序進(jìn)程被殺掉時(shí),所有依賴于該進(jìn)程的Service也會(huì)停止運(yùn)行
后臺服務(wù)
后臺服務(wù)可交互性主要是體現(xiàn)在不同的啟動(dòng)服務(wù)方式,startService()和bindService()。bindService()可以返回一個(gè)代理對象,可調(diào)用Service中的方法和獲取返回結(jié)果等操作,而startService()不行
<a name="t4" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a> 不可交互的后臺服務(wù)
不可交互的后臺服務(wù)即是普通的Service,Service的生命周期很簡單,分別為onCreate、onStartCommand、onDestroy這三個(gè)。當(dāng)我們startService()的時(shí)候,首次創(chuàng)建Service會(huì)回調(diào)onCreate()方法,然后回調(diào)onStartCommand()方法,再次startService()的時(shí)候,就只會(huì)執(zhí)行一次onStartCommand()。服務(wù)一旦開啟后,我們就需要通過stopService()方法或者stopSelf()方法,就能把服務(wù)關(guān)閉,這時(shí)就會(huì)回調(diào)onDestroy()
一、創(chuàng)建服務(wù)類
創(chuàng)建一個(gè)服務(wù)非常簡單,只要繼承Service,并實(shí)現(xiàn)onBind()方法
public class BackGroupService extends Service {
/**
* 綁定服務(wù)時(shí)調(diào)用
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("Service", "onBind");
return null;
}
/**
* 服務(wù)創(chuàng)建時(shí)調(diào)用
*/
@Override
public void onCreate() {
Log.e("Service", "onCreate");
super.onCreate();
}
/**
* 執(zhí)行startService時(shí)調(diào)用
*
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("Service", "onStartCommand");
//這里執(zhí)行耗時(shí)操作
new Thread() {
@Override
public void run() {
while (true){
try {
Log.e("Service", "doSomething");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
return super.onStartCommand(intent, flags, startId);
}
/**
* 服務(wù)被銷毀時(shí)調(diào)用
*/
@Override
public void onDestroy() {
Log.e("Service", "onDestroy");
super.onDestroy();
}
}
二、配置服務(wù)
Service也是四大組件之一,所以必須在manifests中配置
<service android:name=".Service.BackGroupService"/>
<a name="t7" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a>三、啟動(dòng)服務(wù)和停止服務(wù)
我們通過兩個(gè)按鈕分別演示啟動(dòng)服務(wù)和停止服務(wù),通過startService()開啟服務(wù),通過stopService()停止服務(wù)
public class MainActivity extends AppCompatActivity {
Button bt_open, bt_close;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt_open = (Button) findViewById(R.id.open);
bt_close = (Button) findViewById(R.id.close);
final Intent intent = new Intent(this, BackGroupService.class);
bt_open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//啟動(dòng)服務(wù)
startService(intent);
}
});
bt_close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//停止服務(wù)
stopService(intent);
}
});
}
}
當(dāng)你開啟服務(wù)后,還有一種方法可以關(guān)閉服務(wù),在設(shè)置中,通過應(yīng)用->找到自己應(yīng)用->停止
四、運(yùn)行代碼
運(yùn)行程序后,我們點(diǎn)擊開始服務(wù),然后一段時(shí)間后關(guān)閉服務(wù)。我們以Log信息來驗(yàn)證普通Service的生命周期:onCreate->onStartCommand->onDestroy
11-24 00:19:51.483 16407-16407/com.handsome.boke2 E/Service: onCreate
11-24 00:19:51.483 16407-16407/com.handsome.boke2 E/Service: onStartCommand
11-24 00:19:51.485 16407-16613/com.handsome.boke2 E/Service: doSomething
11-24 00:19:53.490 16407-16613/com.handsome.boke2 E/Service: doSomething
11-24 00:19:55.491 16407-16613/com.handsome.boke2 E/Service: doSomething
11-24 00:19:57.491 16407-16613/com.handsome.boke2 E/Service: doSomething
11-24 00:19:58.056 16407-16407/com.handsome.boke2 E/Service: onDestroy
11-24 00:19:59.492 16407-16613/com.handsome.boke2 E/Service: doSomething
11-24 00:20:01.494 16407-16613/com.handsome.boke2 E/Service: doSomething
11-24 00:20:03.495 16407-16613/com.handsome.boke2 E/Service: doSomething
其中你會(huì)發(fā)現(xiàn)我們的子線程進(jìn)行的耗時(shí)操作是一直存在的,而我們Service已經(jīng)被關(guān)閉了,關(guān)閉該子線程的方法需要直接通過Home鍵關(guān)閉該應(yīng)用程序
可交互的后臺服務(wù)
可交互的后臺服務(wù)是指前臺頁面可以調(diào)用后臺服務(wù)的方法,可交互的后臺服務(wù)實(shí)現(xiàn)步驟是和不可交互的后臺服務(wù)實(shí)現(xiàn)步驟是一樣的,區(qū)別在于啟動(dòng)的方式和獲得Service的代理對象
<a name="t10" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a>一、創(chuàng)建服務(wù)類
和普通Service不同在于這里返回一個(gè)代理對象,返回給前臺進(jìn)行獲取,即前臺可以獲取該代理對象執(zhí)行后臺服務(wù)的方法
public class BackGroupService extends Service {
/**
* 綁定服務(wù)時(shí)調(diào)用
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("Service", "onBind");
//返回代理對象
return new MyBinder();
}
/**
* 代理類
*/
class MyBinder extends Binder {
public void showToast() {
Log.e("Service", "showToast");
}
public void showList() {
Log.e("Service", "showList");
}
}
/**
* 解除綁定服務(wù)時(shí)調(diào)用
* @param intent
* @return
*/
@Override
public boolean onUnbind(Intent intent) {
Log.e("Service", "onUnbind");
return super.onUnbind(intent);
}
/**
* 服務(wù)創(chuàng)建時(shí)調(diào)用
*/
@Override
public void onCreate() {
Log.e("Service", "onCreate");
super.onCreate();
}
/**
* 服務(wù)被銷毀時(shí)調(diào)用
*/
@Override
public void onDestroy() {
Log.e("Service", "onDestroy");
super.onDestroy();
}
}
二、配置服務(wù)
<service android:name=".Service.BackGroupService"/>
三、綁定服務(wù)和解除綁定服務(wù)
我們通過兩個(gè)按鈕分別演示綁定服務(wù)和解除綁定服務(wù),通過bindService()開啟服務(wù),通過unbindService()停止服務(wù)
public class MainActivity extends AppCompatActivity {
Button bt_open, bt_close;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt_open = (Button) findViewById(R.id.open);
bt_close = (Button) findViewById(R.id.close);
final Intent intent = new Intent(this, BackGroupService.class);
bt_open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(intent, conn, BIND_AUTO_CREATE);
}
});
bt_close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(conn);
}
});
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//拿到后臺服務(wù)代理對象
BackGroupService.MyBinder myBinder = (BackGroupService.MyBinder) service;
//調(diào)用后臺服務(wù)的方法
myBinder.showToast();
myBinder.showList();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
這里和startService的區(qū)別在于多了一個(gè)ServiceConnection對象,該對象是用戶綁定后臺服務(wù)后,可獲取后臺服務(wù)代理對象的回調(diào),我們可以通過該回調(diào),拿到后臺服務(wù)的代理對象,并調(diào)用后臺服務(wù)定義的方法,也就實(shí)現(xiàn)了后臺服務(wù)和前臺的交互
<a name="t13" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a>四、運(yùn)行代碼
運(yùn)行程序后,我們點(diǎn)擊綁定服務(wù),然后一段時(shí)間后解除綁定服務(wù)。我們以Log信息來驗(yàn)證Service的生命周期:onCreate->onBind->onUnBind->onDestroy,其中也可以看到我們調(diào)用后臺服務(wù)的方法showToast和showList
11-24 00:55:32.775 15408-15408/com.handsome.boke2 E/Service: onCreate
11-24 00:55:32.775 15408-15408/com.handsome.boke2 E/Service: onBind
11-24 00:55:32.796 15408-15408/com.handsome.boke2 E/Service: showToast
11-24 00:55:32.796 15408-15408/com.handsome.boke2 E/Service: showList
11-24 00:55:34.290 15408-15408/com.handsome.boke2 E/Service: onUnbind
11-24 00:55:34.290 15408-15408/com.handsome.boke2 E/Service: onDestroy
混合性交互的后臺服務(wù)
或許你會(huì)迷惑,startService和bindService之間有什么關(guān)系?其實(shí)簡單的說兩者之間是沒有關(guān)聯(lián)的,類似于你親媽生了個(gè)雙胞胎一樣,只有純粹的血緣關(guān)系。那么問題來了,這兩個(gè)啟動(dòng)方式是否可以同時(shí)使用呢,答案是可以的
將上面兩種啟動(dòng)方式結(jié)合起來就是混合性交互的后臺服務(wù)了,即可以單獨(dú)運(yùn)行后臺服務(wù),也可以運(yùn)行后臺服務(wù)中提供的方法,其完整的生命周期是:onCreate->onStartCommand->onBind->onUnBind->onDestroy
<a name="t15" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a> 前臺服務(wù)
由于后臺服務(wù)優(yōu)先級相對比較低,當(dāng)系統(tǒng)出現(xiàn)內(nèi)存不足的情況下,它就有可能會(huì)被回收掉,所以前臺服務(wù)就是來彌補(bǔ)這個(gè)缺點(diǎn)的,它可以一直保持運(yùn)行狀態(tài)而不被系統(tǒng)回收。例如:墨跡天氣在狀態(tài)欄中的天氣預(yù)報(bào)
一、創(chuàng)建服務(wù)類
前臺服務(wù)創(chuàng)建很簡單,其實(shí)就在Service的基礎(chǔ)上創(chuàng)建一個(gè)Notification,然后使用Service的startForeground()方法即可啟動(dòng)為前臺服務(wù)
public class ForegroundService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
showNotification();
}
/**
* 啟動(dòng)前臺通知
*/
private void showNotification() {
//創(chuàng)建通知詳細(xì)信息
Notification.Builder mBuilder = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("2016年11月24日")
.setContentText("今天天氣陰天,8到14度");
//創(chuàng)建點(diǎn)擊跳轉(zhuǎn)Intent
Intent intent = new Intent(this, MainActivity.class);
//創(chuàng)建任務(wù)棧Builder
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
//設(shè)置跳轉(zhuǎn)Intent到通知中
mBuilder.setContentIntent(pendingIntent);
//獲取通知服務(wù)
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//構(gòu)建通知
Notification notification = mBuilder.build();
//顯示通知
nm.notify(0, notification);
//啟動(dòng)為前臺服務(wù)
startForeground(0, notification);
}
}
二、配置服務(wù)
<service android:name=".Service.ForegroundService"/>
<a name="t18" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a>三、啟動(dòng)前臺服務(wù)
startService(new Intent(this, ForegroundService.class));
<a name="t19" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a>四、運(yùn)行代碼
我們可以看到狀態(tài)欄確實(shí)增加了我們這條通知
當(dāng)我們將該程序退出并殺掉的時(shí)候,通過設(shè)置->應(yīng)用->選擇正在運(yùn)行中的應(yīng)用,我們可以發(fā)現(xiàn),我們的程序退出殺掉了,而服務(wù)還在進(jìn)行著
IntentService
IntentService是專門用來解決Service中不能執(zhí)行耗時(shí)操作這一問題的,創(chuàng)建一個(gè)IntentService也很簡單,只要繼承IntentService并覆寫onHandlerIntent函數(shù),在該函數(shù)中就可以執(zhí)行耗時(shí)操作了
public class TheIntentService extends IntentService {
public TheIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
//在這里執(zhí)行耗時(shí)操作
}
}
AIDL跨進(jìn)程服務(wù)
關(guān)于AIDL跨進(jìn)程服務(wù)的使用和原理分析,可以見我另一篇博客:Android基礎(chǔ)——初學(xué)者必知的AIDL在應(yīng)用層上的Binder機(jī)制
<a name="t22" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a> AccessibilityService無障礙服務(wù)
關(guān)于AccessibilityService無障礙服務(wù)的使用和實(shí)例,可以見我另一篇博客:Android進(jìn)階——學(xué)習(xí)AccessibilityService實(shí)現(xiàn)微信搶紅包插件
<a name="t23" target="_blank" style="text-decoration: none; box-sizing: border-box; color: rgb(12, 137, 207);"></a> 系統(tǒng)服務(wù)
系統(tǒng)服務(wù)提供了很多便捷服務(wù),可以查詢Wifi、網(wǎng)絡(luò)狀態(tài)、查詢電量、查詢音量、查詢包名、查詢Application信息等等等相關(guān)多的服務(wù),具體大家可以自信查詢文檔,這里舉例幾個(gè)常見的服務(wù)
1. 判斷Wifi是否開啟
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
boolean enabled = wm.isWifiEnabled();
需要權(quán)限
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
2. 獲取系統(tǒng)最大音量
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
int max = am.getStreamMaxVolume(AudioManager.STREAM_SYSTEM);
3. 獲取當(dāng)前音量
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
int current = am.getStreamMaxVolume(AudioManager.STREAM_RING);
4. 判斷網(wǎng)絡(luò)是否有連接
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
boolean isAvailable = info.isAvailable();
需要權(quán)限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
部分源碼下載