bindService的過程要比startService的過程復(fù)雜一些,因?yàn)閎ingService之后,發(fā)起者可以跨進(jìn)程調(diào)用service的某些方法。而startService啟動service之后诊县,發(fā)起者僅能去終止service,而不能調(diào)用service的方法措左。
既然發(fā)起者可以跨進(jìn)程調(diào)用service中的方法依痊,那么肯定要用到binder了。本文也會重點(diǎn)分析binder的傳遞過程怎披,至于binder的機(jī)制胸嘁,后面在單獨(dú)開篇介紹。使用bindService啟動的service的開發(fā)過程中一般都會借助aidl凉逛。這里不介紹aidl性宏,因?yàn)檫@不是本文的重點(diǎn)。
當(dāng)一個(gè)app進(jìn)程bindService()時(shí)状飞,它需要先準(zhǔn)備好一個(gè)實(shí)現(xiàn)了ServiceConnection接口的對象毫胜。ServiceConnection的定義如下:
public interface ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service);
public void onServiceDisconnected(ComponentName name);
}
bindService()見名知意即綁定服務(wù),建立一個(gè)邏輯連接诬辈。當(dāng)連接建立之后酵使,AMS會回調(diào)ServiceConnection接口對象的onServiceConnected()方法。把遠(yuǎn)端service的代理binder傳遞過來自晰,這樣就可以通過這個(gè)代理binder跨進(jìn)程調(diào)用service中的方法了凝化。
ServiceConnection接口的onServiceDisconnected()方法并不會在unbindService()操作斷開邏輯連接時(shí)執(zhí)行。而是在遠(yuǎn)端service進(jìn)程終止時(shí)酬荞,AMS才會回調(diào)onServiceDisconnected()搓劫。
另外要注意的是縱然service進(jìn)程的因?yàn)槟承┰虮唤K止瞧哟,之前的綁定在該service上的邏輯連接仍處于激活狀態(tài),當(dāng)service再次運(yùn)行的時(shí)候枪向,AMS會回調(diào)onServiceConnected勤揩。
bindService的過程,我們要關(guān)心的binder有兩個(gè)秘蛔,一個(gè)是遠(yuǎn)端service的binder陨亡,有了它客戶端進(jìn)程才能跨進(jìn)程調(diào)用service中的方法;另一個(gè)是binder是客戶端傳遞給AMS的深员,有了這個(gè)binder负蠕,AMS才會在邏輯連接建立之后,跨進(jìn)程調(diào)用客戶端中的ServiceConnection接口的對象中的onServiceConnected()和onServiceDisconnected()倦畅。
要明白bindservice的過程遮糖,就必須搞清楚這兩個(gè)binder的傳遞過程他。
另外bindservice在建立連接時(shí)叠赐,如果發(fā)現(xiàn)service還沒啟動欲账,會根據(jù)flag是否設(shè)置BIND_AUTO_CREATE,決定是否啟動這個(gè)service芭概。
同startService()一樣赛不,bindService()也是一個(gè)異步的過程,也就是說當(dāng)該方法返回時(shí)罢洲,邏輯連接很可能還沒有建立踢故,通俗的說就是該方法返回時(shí),onServiceConnected()方法很可能還沒執(zhí)行惹苗。
app的service和系統(tǒng)的service
系統(tǒng)中的servcice都是由ServiceManager負(fù)責(zé)管理的畴椰。系統(tǒng)中的service在啟動的時(shí)候,都會向ServiceManager注冊鸽粉。
App進(jìn)程要使用這些系統(tǒng)service時(shí),比如AMS抓艳,可以向ServiceManager通過service名字查詢触机。ServiceManager會返回這個(gè)service的一個(gè)代理binder。這樣便可以向service發(fā)起調(diào)用請求了玷或。
但是app是沒有權(quán)限向ServiceManager注冊service的儡首。所以只能另辟蹊徑。bindService要負(fù)責(zé)找到service的代理binder并傳遞到app進(jìn)程偏友。這期間涉及到binder實(shí)體的跨進(jìn)程傳輸蔬胯,也就是所謂的匿名binder。因?yàn)檫@些binder并沒有在ServiceManager中注冊位他。
bindService的過程
整個(gè)過程大體上是這樣的:
檢查要綁定的額service是否啟動氛濒,沒有的話产场,要先啟動service,然后執(zhí)行service的生命周期方法舞竿。
執(zhí)行綁定京景,先將遠(yuǎn)端service的binder傳遞到AMS中,然后AMS在將其傳遞到客戶端組件進(jìn)程中
ContextImpl.bindService():
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
ContextImpl.bindServiceCommon():
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
................
if (mPackageInfo != null) {
//從LoadedApk中拿到一個(gè)binder實(shí)體
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
// Android5.0之后不允許使用隱式調(diào)用
// 這里對傳入的intetn進(jìn)行檢查骗奖,如果是android5.0以上确徙,
//是隱式intent的話拋出異常
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
....................
service.prepareToLeaveProcess();
// 向AMS發(fā)起跨進(jìn)程調(diào)用其bindService方法
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
..............................
return res != 0;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
這里便引出了第一個(gè)binder:IServiceConnection sd。這是一個(gè)實(shí)體binder执桌,也就是說跨進(jìn)程傳輸?shù)紸MS進(jìn)程之后鄙皇,AMS進(jìn)程中最終得到的是一個(gè)代理binder。而且binder實(shí)體跨進(jìn)程傳輸過程中仰挣,會在binder驅(qū)動層中為其創(chuàng)建相應(yīng)的數(shù)據(jù)結(jié)構(gòu)伴逸,這樣binder便在binder驅(qū)動中扎根了。
那么這個(gè)binder實(shí)體最初是從哪里來的呢椎木?
客戶端組件中用來調(diào)度綁定操作的ServiceDispatcher對象
此處的mPackageInfo是用戶進(jìn)程里和apk對應(yīng)的LoadedApk對象违柏,前面所說的第一個(gè)binder實(shí)體由LoadedApk.getServiceDispatcher()獲得:
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
// 先從LoadedApk.mService中查找,
// 看看發(fā)起綁定操作的組件是否已經(jīng)存在一個(gè)用來處理傳入的
//ServiceConnection接口對象的ServiceDispatcher
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
// 存在的話直接返回這個(gè)ServiceDispatcher
sd = map.get(c);
}
if (sd == null) {
// 不存在的話創(chuàng)建一個(gè)ServiceDispatcher
// 這里要注意第三個(gè)參數(shù)handler香椎,是主線程的handler
// 保存在了ServiceDispatcher.mActivityThread中
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
// 將創(chuàng)建的ServiceDispatcher緩存到LoadedApk.mService
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
LoadedApk.ServiceDispatcher從它的名字中可以看出它類似于一個(gè)Dispatcher的作用漱竖,這個(gè)類的作用就是當(dāng)client bind某個(gè)service成功之后,負(fù)責(zé)向client分配service IBinder的畜伐;以及當(dāng)client unbind service時(shí)馍惹,負(fù)責(zé)通知client unbind service的狀態(tài)。
對于ServiceDispatcher的管理玛界,是以apk万矾,即package為載體的,也就是說對于某個(gè)package慎框,定義在其中的component如果請求去bind一個(gè)service良狈,那么LoadedApk將為這個(gè)component分配一個(gè)ServiceDispatcher。
component每請求bind一個(gè)service笨枯,都會為其指定一個(gè)ServiceConnection接口的對象薪丁,同一component組件內(nèi),LoadedApk將會為這個(gè)ServiceConnection接口的對象分配一個(gè)唯一的ServiceDispatcher馅精。但是不同component組件中严嗜,就算是使用同一個(gè)ServiceConnection接口的對象,LoadedApk中也會為這個(gè)對象分配兩個(gè)ServiceDispatcher對象洲敢。
也就是說漫玄,ServiceDispatcher是客戶端組件相關(guān)的一個(gè)概念。
每個(gè)app進(jìn)程中是可以加載多個(gè)apk包的压彭,記錄在ActivityThread.mPackages,整個(gè)關(guān)系如下所示:
packages中的組件component睦优,例如某個(gè)activity中使用bindService去綁定一個(gè)service時(shí)渗常,都需要提供一個(gè)實(shí)現(xiàn)ServiceConnection接口的對象,每一個(gè)這樣的對象都會與一個(gè)ServiceDispatcher對象綁定刨秆。
LoadedApk.mServices中存儲了本package中所有組件中所有的ServiceDispatcher凳谦。它是一個(gè)ArrayMap,key是context衡未,實(shí)際上就是組件尸执,因?yàn)榻M件繼承自Context。value又是一個(gè)ArrayMap缓醋,因?yàn)橐粋€(gè)組件中使可以綁定多個(gè)service的嘛如失。這個(gè)map的可以是實(shí)現(xiàn)了ServiceConnection接口的對象,value是與之綁定的ServiceDispatcher對象送粱。
現(xiàn)在可以看看這個(gè)ServiceDispatcher到底是個(gè)什么東東了:
static final class ServiceDispatcher {
// 一個(gè)binder實(shí)體對象
private final ServiceDispatcher.InnerConnection mIServiceConnection;
// 邏輯連接建立時(shí)褪贵,執(zhí)行的回調(diào)接口對象
private final ServiceConnection mConnection;
// 所在的組件,即client
private final Context mContext;
// 進(jìn)程主線程即UI線程中的handler
private final Handler mActivityThread;
private final ServiceConnectionLeaked mLocation;
// 綁定service時(shí)抗俄,傳入的flag脆丁,例如BIND_AUTO_CREATE
private final int mFlags;
private RuntimeException mUnbindLocation;
private boolean mDied;
private boolean mForgotten;
// 因?yàn)橐粋€(gè)ServiceConnection可以被bindService方法多次調(diào)用,用來啟動不同的service动雹,
// 那么ServiceDispatcher中自然要存儲這些連接信息了:
// ConnectionInfo很簡單只有兩個(gè)屬性成員
// IBinder binder;遠(yuǎn)端service的引用binder
// IBinder.DeathRecipient deathMonitor; 遠(yuǎn)端binder的死亡通知方法
private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
= new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
................
}
ServiceDispatcher.InnerConnection是一個(gè)繼承自 IServiceConnection.Stub的binder實(shí)體類:
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service);
}
}
}
其中ServiceDispatcher.connected():
public void connected(ComponentName name, IBinder service) {
// 這里的mActivityThread是主線程的handler
// 也就是說槽卫,實(shí)際上ServiceConnection中的回調(diào)是在主線程中執(zhí)行的
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0));
} else {
doConnected(name, service);
}
}
ServiceDispatcher.InnerConnection是一個(gè)繼承自 IServiceConnection.Stub的binder實(shí)體類,從其名字上來看是一個(gè)內(nèi)部連接胰蝠,該怎么理解呢歼培?
因?yàn)閎indService()傳遞的ServiceConnection接口對象,并沒有跨進(jìn)程傳輸?shù)紸MS中茸塞,從bindServiceCommon()方法可以看出最終傳遞到AMS的是LoadedApk.getServiceDispatcher()返回的ServiceDispatcher.InnerConnection躲庄。AMS通過它跨進(jìn)程間接調(diào)用ServiceConnection中的方法。
因?yàn)橐粋€(gè)ServiceConnection可以在同一個(gè)客戶端組件內(nèi)被bindService方法多次調(diào)用钾虐,用來綁定不同的service噪窘,那么ServiceDispatcher中自然要存儲這些使用同一個(gè)serviceConnection綁定的service的連接信息了——ServiceDispatcher.mActiveConnections。
它是ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>類型對象效扫,
private static class ConnectionInfo {
// 遠(yuǎn)端service的代理binder
IBinder binder;
// 遠(yuǎn)端service 死亡通知回調(diào)
IBinder.DeathRecipient deathMonitor;
}
AMS中綁定service過程
ContextImpl.bindServiceCommon()方法中得到ServiceConnection對應(yīng)的ServiceDispatcher對象之后效览,便向AMS發(fā)起請求,跨進(jìn)程調(diào)用AMS.bindService():
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
..............
synchronized(this) {
// mServices是ActiveService
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
AMS.bindService()對參數(shù)做了簡單檢查之后荡短,又調(diào)用ActiveService.bindServiceLocked()方法。
這里先對ActiveService.bindServiceLocked()方法的幾個(gè)重要參數(shù)做一些說明:
int bindServiceLocked(
IApplicationThread caller, // 客戶端進(jìn)程ActivityThread.mAppThread的代理binder
IBinder token,
Intent service,// 客戶端綁定service時(shí)的intent
String resolvedType,
IServiceConnection connection, //客戶端進(jìn)程的中ServiceDispatcher.InnerConnection的代理binder
int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
ActiveService.bindServiceLocked()與上一篇介紹的startService的ActiveService.startServiceLocked()方法中有很多相似的邏輯哆键。
比如同樣是要先查找要啟動的servicee在AMS中的代表ServiceRecord是否存在掘托,存在的話弟疆,意味著service已經(jīng)啟動泪勒;不存在的話吕嘀,要創(chuàng)建一個(gè)ServiceRecord對象障斋,這些操作還是由retrieveServiceLocked()方法負(fù)責(zé)的。然后通過bringUpServiceLocked()調(diào)用service的生命周期方法泪掀。只不過bindservice除了這兩個(gè)基本操作外听绳,還要執(zhí)行綁定操作,即將service的binder傳跨進(jìn)程傳輸?shù)絘pp客戶端組件中异赫。
綁定前的準(zhǔn)備工作
執(zhí)行綁定操作前椅挣,要先做一些準(zhǔn)備工作,比如在AMS中記錄客戶端和service的一些信息塔拳,下面的代碼就是做這些事情的:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
...............
// 得到service對應(yīng)的ServiceRecord
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
ServiceRecord s = res.record;
....
// 根據(jù)傳入的intent和發(fā)起者進(jìn)程鼠证,查找到一個(gè)合適的AppBindRecord對象,
// 查找不到就創(chuàng)建一個(gè)靠抑,下面會介紹規(guī)則
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
// 為本次連接創(chuàng)建ConnectionRecord對象
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
// 客戶端進(jìn)程的中ServiceDispatcher.InnerConnection的代理binder
IBinder binder = connection.asBinder();
// 將創(chuàng)建的邏輯連接對象ConnectionRecord量九,記錄在ServiceRecord中
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);
// 同時(shí)記錄在AppBindRecord.connections中
b.connections.add(c);
// AppBindRecord.client是ProcessRecord,代表客戶端的進(jìn)程
b.client.connections.add(c);
.......
// 除了ServiceRecord.connections記錄了該service連接信息外
// ActiveService.mServiceConnections記錄了當(dāng)前系統(tǒng)中所有的連接信息
// 所以也要將創(chuàng)建的連接對象,加入ActiveService.mServiceConnections
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
............
在前面關(guān)于service機(jī)制介紹的文章中提到過ServiceRecord中有一些數(shù)據(jù)成員是bindservice時(shí)用到的:
final class ServiceRecord extends Binder {
...............
final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
= new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();// IBinder -> ConnectionRecord of all bound clients
// service所在的進(jìn)程
ProcessRecord app; // where this service is running or null.
}
AMS描述綁定service時(shí)的intent的IntentBindRecord類
app客戶端組件中發(fā)起綁定service操作時(shí)颂碧,一定要用到intent荠列,一般是顯示的intent(android 5.0 之后要求必須是顯示intent),而且只設(shè)置intetn.mComponent字段载城。
AMS中對綁定操作傳入的intent是用Intent.FilterComparison類來描述,也就是說當(dāng)客戶端綁定service時(shí)使用的intent指定的參數(shù)都一致的話肌似,AMS會將其看做是同一類intent。
AMS會為這類intent為其創(chuàng)建一個(gè)IntentBindRecord對象个曙。
final class IntentBindRecord {
// 綁定的service在AMS中的代表
final ServiceRecord service;
/** The intent that is bound.*/
final Intent.FilterComparison intent; //
/** All apps that have bound to this Intent. */
final ArrayMap<ProcessRecord, AppBindRecord> apps
= new ArrayMap<ProcessRecord, AppBindRecord>();
// service的binder代理binder
IBinder binder;
其中IntentBindRecord.service 最終會保存綁定的service的ServiceRecord锈嫩;
IntentBindRecord.intent 就是前面所說的綁定service時(shí)設(shè)定的參數(shù)一致的intent在AMS中的表示Intent.FilterComparison對象;
IntentBindRecord.apps用來記錄所有使用該類intetn綁定同一個(gè)service的客戶端信息垦搬。key是客戶端進(jìn)程ProcessRecord呼寸,value是AppBindRecord。因?yàn)椴煌目蛻舳丝赡苁褂孟嗤膇ntent參數(shù)來綁定同一個(gè)service,所以IntentBindRecord要記錄下這些客戶端信息猴贰;
IntentBindRecord.binder最終保存service的代理binder对雪;
AMS通過ServiceRecord.retrieveAppBindingLocked()方法為判斷是否為傳入的intent創(chuàng)建一個(gè)IntentBindRecord:
public AppBindRecord retrieveAppBindingLocked(
Intent intent,// 客戶端發(fā)起綁定操作時(shí)傳入的intent
ProcessRecord app // 客戶端組件進(jìn)程) {
// 為傳入的intent創(chuàng)建一個(gè)Intent.FilterComparison
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
// 查找傳入的intent是否已經(jīng)有IntentBindRecord
IntentBindRecord i = bindings.get(filter);
if (i == null) {
// 沒有的話創(chuàng)建
i = new IntentBindRecord(this, filter);
//并緩存到ServiceRecord.bings中
bindings.put(filter, i);
}
// 查找客戶端的組件是否已經(jīng)綁定過該service
AppBindRecord a = i.apps.get(app);
// 綁定過的話,返回找到的AppBindRecord
if (a != null) {
return a;
}
// 沒有的話創(chuàng)建一個(gè)AppBindRecord對象
a = new AppBindRecord(this, i, app);
// 并緩存到IntentBindRecord.apps中
i.apps.put(app, a);
return a;
}
retrieveAppBindingLocked()另一個(gè)主要作用是查找并創(chuàng)建AppBindRecord對象米绕。
AMS用于描述綁定service的客戶端整體信息的AppBindRecord類
對于一個(gè)Service來說瑟捣,有多少app客戶端進(jìn)程和它建立了綁定關(guān)系,就會有多少個(gè)AppBindRecord對象栅干。一個(gè)app客戶端進(jìn)程里可以有多個(gè)地方發(fā)起綁定動作迈套,所以AppBindRecord里需要用一個(gè)ArraySet<ConnectionRecord>記錄下每個(gè)綁定動作對應(yīng)的邏輯連接對象。
final class AppBindRecord {
// 所在的service
final ServiceRecord service; // The running service.
// 客戶端發(fā)起的bindservice時(shí)傳入的intent碱鳞,AMS會為其創(chuàng)建一個(gè)對應(yīng)的IntentBindRecord
final IntentBindRecord intent; // The intent we are bound to.
// 客戶端進(jìn)程
final ProcessRecord client; // Who has started/bound the service.
// 客戶端所在的app桑李,其他組件綁定該service的邏輯連接
final ArraySet<ConnectionRecord> connections = new ArraySet<>();
// All ConnectionRecord for this client.
AppBindRecord.service 用于描述客戶端綁定的service;
AppBindRecord.intent 用于描述客戶端綁定該service時(shí)使用的intent;
AppBindRecord.client 用于描述客戶端的進(jìn)程贵白;
AppBindRecord.connections 用于描述客戶端中所有組件綁定該service時(shí)創(chuàng)建的邏輯連接率拒;
AMS通過ServiceRecord.retrieveAppBindingLocked()來查找并創(chuàng)建一個(gè)合適的AppBindRecord對象。
描述綁定連接的ConnectionRecord類
AMS為每次綁定過程中創(chuàng)建的連接分配一個(gè)ConnectionRecord類型對象.
ConnectionRecord用來描述一個(gè)連接信息禁荒,即綁定信息猬膨,要對客戶端和service端進(jìn)行描述。
/**
* Description of a single binding to a service.
*/
final class ConnectionRecord {
// 記錄客戶端綁定的信息
final AppBindRecord binding; // The application/service binding.
// 這里是綁定服務(wù)的客戶端的一個(gè)binder呛伴,通過它可以調(diào)用客戶端的方法
// ServiceConnection.onServiceConnected()
final IServiceConnection conn; // The client connection.
final int flags; // Binding options.
ConnectionRecord.binding代表這個(gè)連接所在的AppBindRecord.
ConnectionRecord.coon是一個(gè)binder代理對象勃痴,其實(shí)體binder是app進(jìn)程中ServiceDispatcher.mIServiceConnection。用來回調(diào)客戶端進(jìn)程中當(dāng)連接成功建立時(shí)的回調(diào)方法磷蜀。
客戶端組件在bindservice時(shí)召耘,都要創(chuàng)建一個(gè)實(shí)現(xiàn)ServiceConnection接口的對象,每個(gè)這樣的對象在客戶端組件所在的LoadedApk中都會分配一個(gè)ServiceDispatcher對象褐隆,這個(gè)對象用于處理所有使用該ServiceConnection接口的對象綁定service的客戶端組件的回調(diào)方法的執(zhí)行污它。
ConnectionRecord.flags 用于描述綁定該service時(shí),指定的flags庶弃,例如BIND_AUTO_CREATE.
AMS創(chuàng)建的ConnectionRecord對象會存儲在ServiceRecord.connections成員變量中.
ServiceRecord.connections是一個(gè)map衫贬,key是ServiceDispatcher.InnerConnection的代理binder,value是ArrayList<ConnectionRecord>類型的歇攻。
因?yàn)榭蛻舳诉M(jìn)程中一個(gè)Component中可能使用同一個(gè)ServiceConnection接口對象來多次綁定同一個(gè)service固惯,因?yàn)槊看谓壎ǘ紩?chuàng)建一個(gè)ConnectionRecord對象,那么這些ConnectionRecord需要使用ArrayList<ConnectionRecord>來保存缴守。
value中ConnectionRecord.IServiceConnection實(shí)際上一致與key是一致的葬毫。
AMS除了將這個(gè)"邏輯連接"ConnectionRecord對象,記錄在ServiceRecord.connections中外屡穗,還要向至少下面的幾處位置做記錄:
客戶端所在的進(jìn)程在AMS中的代表ProcessRecord.connections
ActiveService.mServiceConnections,這里面記錄了AMS中所有app的service的連接
AppBindRecord.connections中
之所以要在這么多地方做記錄贴捡,可能是為了在不同的場合下迅速查找到連接吧。
了解了以上內(nèi)容后村砂,就可以通過下圖簡明的描述客戶端進(jìn)程和AMS之間的關(guān)系:
執(zhí)行service生命周期方法
在做好前面的準(zhǔn)備工作之后烂斋,binderservice()就開始準(zhǔn)備與Service建立連接了。那么自然要先對service進(jìn)行一些操作础废,說白了就是執(zhí)行service的生命周期方法汛骂,這是由bringUpServiceLocked()方法來負(fù)責(zé)的。
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
.................
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
// 只有當(dāng)要綁定的service所在的進(jìn)程還啟動的時(shí)候评腺,該方法返回非null
// 因?yàn)閱舆M(jìn)程需要一段時(shí)間帘瞭,所以就要先退出來
// 這里暫時(shí)假設(shè)service所在的進(jìn)程已經(jīng)啟動
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
return 0;
}
}
....................
此時(shí)可以分為兩大情況:
service進(jìn)程還沒啟動
service進(jìn)程已經(jīng)啟動,此時(shí)有可分為兩種情況:service還沒啟動和service已經(jīng)運(yùn)行蒿讥。
bringUpServiceLocked()方法依據(jù)ServiceRecord.app區(qū)分以上兩大情況:
1.ServiceRecord.app不為null图张,而且ServiceRecord.app.thread也不為null锋拖,預(yù)示著service已經(jīng)運(yùn)行了,但是這時(shí)候并不會向startService()啟動service那樣跨進(jìn)程調(diào)用service.onStartCommand()生命周期方法祸轮,因?yàn)閎indService啟動service時(shí)沒有將信息記錄到ServiceRecord.pendingStarts。
2.ServiceRecord.app為null侥钳,說明ServiceRecord還沒有和service所在的進(jìn)程關(guān)聯(lián)适袜。
此時(shí)在依據(jù)ServiceRecord.processName,也就是service要求運(yùn)行在的進(jìn)程的名字,在AMS中查找是否有這樣的進(jìn)程存在舷夺,如果有的話苦酱,只需要啟動service,也就是在找到的進(jìn)程中創(chuàng)建service對象给猾,并執(zhí)行service.onCreate()生命周期方法疫萤。
以上兩種情況的詳細(xì)過程,參考前一篇文章敢伸。
如果沒有在AMS中找到名字為ServiceRecord.processName的進(jìn)程扯饶,那么就要先創(chuàng)建進(jìn)程了,這里不考慮這種情況池颈。
綁定service
綁定實(shí)際上就是想辦法拿到service的binder尾序,并將其傳遞到客戶端組件進(jìn)程,另外還要對前面準(zhǔn)備工作期間創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)設(shè)置相關(guān)的字段躯砰。
這部分代碼如下:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
.................
// b.intent.received為true每币,表明已經(jīng)拿到了service的binder
f (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
// 這里就可以直接遠(yuǎn)程調(diào)用客戶端組件中onServiceConnected()方法將service的binder傳遞過去了
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
// 之前沒綁定過,那么就調(diào)用下面的額方法進(jìn)行綁定
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
這里分兩種情況:
客戶端組件之前已經(jīng)綁定過該service琢歇,現(xiàn)在這個(gè)組件又要再次綁定兰怠,也就是客戶端同一組件重復(fù)綁定
客戶端組件首次綁定該service
這兩種情況的區(qū)分是依據(jù)AppBindRecord.intent,即AMS為bindservice()傳入的intent分配的IntentBindRecord對象來決定的李茫。
final class IntentBindRecord {
/** Binder published from service. */
IBinder binder;
/** Set when we have initiated a request for this binder. */
boolean requested;
/** Set when we have received the requested binder. */
boolean received;
/** Set when we still need to tell the service all clients are unbound. */
boolean hasBound;
}
IntentBindRecord.received為true揭保,表明IntentBindRecord.binder已經(jīng)指向遠(yuǎn)端service的binder;
IntentBindRecord.requested為false涌矢,表明IntentBindRecord.binder還沒有指向遠(yuǎn)端service的binder掖举;
這里分析第二種情況,時(shí)序圖如下:
requestServiceBindingLocked()方法中跨進(jìn)程調(diào)用service所在的進(jìn)程中方法,最終會導(dǎo)致service.onBind()執(zhí)行娜庇,該方法返回service的實(shí)體binder塔次。
這里有一點(diǎn)要貼別注意,那只要service被某個(gè)客戶端組件綁定過了名秀,就不會再執(zhí)行service.onBind()方法了励负,原因就在requestServiceBindingLocked()方法中:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
..............
// 傳入的rebind為false還是true,取決于AMS調(diào)用service.onUnbind()返回值
// 如果希望客戶端下一次綁定到服務(wù)時(shí)接收 onRebind() 調(diào)用(而不是接收 onBind() 調(diào)用)匕得,onUnbind()返回true
// service首次被綁定時(shí)继榆,rebind肯定為false
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
// 跨進(jìn)程調(diào)用service所在進(jìn)程的scheduleBindService()方法巾表,執(zhí)行綁定操作,這是一個(gè)異步方法略吨,會立即返回
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
// 只要service被綁定過了集币,IntentBindRecord.requested就會被設(shè)置為true
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
.................
} catch (RemoteException e) {
.................
}
}
return true;
}
通過以上代碼可知,只要service被綁定過一次翠忠,那么IntentBindRecord.requested救回被設(shè)置為true鞠苟,其他客戶端組件再次綁定的時(shí)候,由于if條件為假秽之,所以不會再次跨進(jìn)程調(diào)用service進(jìn)程中的scheduleBindService()方法当娱,也就不會調(diào)用service.onBind()方法了。
因?yàn)閎indservice時(shí)傳入的intent一般都是顯示intent考榨,不會設(shè)置其他參數(shù)跨细,所以只要客戶端綁定的是同一個(gè)service,那么在AMS中只會有一個(gè)IntentBindRecord對象河质。
除非該servcie綁定過之后冀惭,所有綁定它的客戶端組件都執(zhí)行了unbindService(),那么最終會導(dǎo)致service.onUnbind()方法執(zhí)行愤诱,如果該方法返回了true云头,那么下次再有客戶端組件綁定該service時(shí),rebind會被設(shè)置為true淫半,這導(dǎo)致不會調(diào)用service.onBind()溃槐,而是調(diào)用service.rebind()方法。如下代碼所示:
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
// 傳入flase時(shí)執(zhí)行onBind()
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
// 傳入true時(shí)執(zhí)行onRebind()
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
這里考慮首次綁定時(shí)的情況科吭,所以rebind肯定為false昏滴,那么service調(diào)用過onBind()之后,又通過AMS的代理对人,跨進(jìn)程調(diào)用AMS的publishService()將service的binder傳遞到AMS中谣殊,然后在傳遞到客戶端。
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
.......
IntentBindRecord b = r.bindings.get(filter);
// 初次綁定
if (b != null && !b.received) {
// 保存service的代理binder
b.binder = service;
// 設(shè)置下面的兩個(gè)標(biāo)志為true
b.requested = true;
b.received = true;
// 一般情況下牺弄,首次綁定時(shí)姻几,connections.size為1
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Published intent: " + intent);
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
// 將service的binder傳遞到客戶端
c.conn.connected(r.name, service);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
}
}
}
...........
那么當(dāng)首次綁定之后,又有其他客戶端組件來綁定這個(gè)service势告,那么在bindServiceLocked()方法中蛇捌,會直接跨進(jìn)程調(diào)用客戶端的connected():
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
................
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
// 直接跨進(jìn)程調(diào)用客戶端的connected()
// 不在需要跨進(jìn)程調(diào)用service.onBind()
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
..........................
}
在看客戶端進(jìn)程的connected()
public void connected(ComponentName name, IBinder service) throws RemoteException {
// 先得到處理ServiceConnection的ServiceDispatcher
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service);
}
}
public void connected(ComponentName name, IBinder service) {
// mActivityThread是在創(chuàng)建 ServiceDispatcher對象時(shí),傳入的組件所在進(jìn)程的主線程的handler
// 也就是說RunConnection是在組件所在的主線程中執(zhí)行的
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0));
} else {
doConnected(name, service);
}
}
RunConnection.run()中會調(diào)用LoadedApk.doConnected()方法:
public void run() {
if (mCommand == 0) {
doConnected(mName, mService);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
LoadedApk.doConnected():
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
.....................
ServiceDispatcher.ConnectionInfo old;
//很有意思咱台,也就是說同一組件中對同一個(gè)service重復(fù)綁定络拌,onServiceConnected()只會執(zhí)行一次
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
// Huh, already have this one. Oh well!
return;
}
if (service != null) {
// A new service is being connected... set it all up.
mDied = false;
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
// 設(shè)置死亡回調(diào)
service.linkToDeath(info.deathMonitor, 0);
// 將info保存在LoadedApk.mActiveConnections
mActiveConnections.put(name, info);
} catch (RemoteException e) {
// This service was dead before we got it... just
// don't do anything with it.
mActiveConnections.remove(name);
return;
}
} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// If there was an old service, it is not disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
// If there is a new service, it is now connected.
if (service != null) {
// 執(zhí)行回調(diào)
mConnection.onServiceConnected(name, service);
}
}
doConnected()比較有意思的是下面的代碼:
ServiceDispatcher.ConnectionInfo old;
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
// Huh, already have this one. Oh well!
return;
}
mActiveConnections來自ServiceDispatcher:
private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
= new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
ServiceDispatcher.mActiveConnections用來記錄該LoadedApk中的組件所綁定的service的連接信息。key是service的組件名回溺,value是ServiceDispatcher.ConnectionInfo春贸。
ConnectionInfo中記錄了service的代理binder以及死亡通知回調(diào)混萝。
private static class ConnectionInfo {
// 遠(yuǎn)端service的代理binder
IBinder binder;
// 遠(yuǎn)端service 死亡通知回調(diào)
IBinder.DeathRecipient deathMonitor;
}
connected(ComponentName name, IBinder service)方法的第一個(gè)參數(shù)是service的組件名,第二個(gè)參數(shù)是service的代理binder萍恕。
connected()方法中首先以name為key在mActiveConnections查找逸嘀,如果索引到的ConnectionInfo的binder與傳入的binder一致的話,說明是同一組件內(nèi)使用同一個(gè)ServiceConnection接口對象對同一個(gè)service重復(fù)綁定允粤,此時(shí)不會執(zhí)行onServiceConnected()方法厘熟。
unbindeService
現(xiàn)在在看一下unbindeService()的過程,直接看AMS.unbindServiceLocked()维哈,整個(gè)過程大體上就是找到相關(guān)的連接對象ConnectionRecord,將其從相關(guān)的map中移除,然后根據(jù)情況決定是否調(diào)用serive.onUnbind生命周期方法
boolean unbindServiceLocked(IServiceConnection connection) {
// 得到ServiceDispatcher.InnerConnection的binder
IBinder binder = connection.asBinder();
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
// 前面說了ActiveService.mServiceConnections,這里面記錄了AMS中所有app的service的連接
// 自然也包括同一組件內(nèi)使用同一個(gè)ServiceConnection綁定同一個(gè)service的情況
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
// 說明沒有使用該ServiceConnection接口對象綁定過service
// 所以無需unbind
if (clist == null) {
Slog.w(TAG, "Unbind failed: could not find connection for "
+ connection.asBinder());
return false;
}
final long origId = Binder.clearCallingIdentity();
try {
// 依次取出同一組件內(nèi)使用該ServiceConnection接口對象綁定的service的連接信息對象ConnectionRecord
// 這里要注意的是登澜,這相當(dāng)于在發(fā)起unbindService()操作的組件中阔挠,對所有使用該ServiceConnection接口對象綁定的sercvice
// 發(fā)起unbindService操作
while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
removeConnectionLocked(r, null, null);
if (clist.size() > 0 && clist.get(0) == r) {
// In case it didn't get removed above, do it now.
Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
clist.remove(0);
}
if (r.binding.service.app != null) {
// This could have made the service less important.
if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
r.binding.service.app.treatLikeActivity = true;
mAm.updateLruProcessLocked(r.binding.service.app,
r.binding.service.app.hasClientActivities
|| r.binding.service.app.treatLikeActivity, null);
}
mAm.updateOomAdjLocked(r.binding.service.app);
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return true;
}
再看removeConnectionLocked():
void removeConnectionLocked(
ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
// 從ServiceRecord中取出所有綁定該service的連接
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist != null) {
// 將使用要unbindService()的ServiceConnection創(chuàng)建的連接
// 從ServiceRecord.connections中移除
clist.remove(c);
if (clist.size() == 0) {
s.connections.remove(binder);
}
}
// 將使用要unbindService()的ServiceConnection創(chuàng)建的連接
// 從AppBindRecord.connections中移除
b.connections.remove(c);
if (c.activity != null && c.activity != skipAct) {
if (c.activity.connections != null) {
c.activity.connections.remove(c);
}
}
if (b.client != skipApp) {
b.client.connections.remove(c);
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.updateHasAboveClientLocked();
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
}
clist = mServiceConnections.get(binder);
if (clist != null) {
// 將使用要unbindService()的ServiceConnection創(chuàng)建的連接
// 從ActiveService.mServiceConnections中移除
clist.remove(c);
if (clist.size() == 0) {
mServiceConnections.remove(binder);
}
}
mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);
// 如果AppBindRecord.connections.size為0
// 表示某客戶端已經(jīng)沒有組件與該service綁定了
// 那么將客戶端從IntentBindRecord.apps中移除
if (b.connections.size() == 0) {
b.intent.apps.remove(b.client);
}
if (!c.serviceDead) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
+ ": shouldUnbind=" + b.intent.hasBound);
// 如果IntentBindRecord.apps.size為0,表示沒有客戶端與該service綁定了
// 那么開始回調(diào)service進(jìn)程的scheduleUnbindService()脑蠕,執(zhí)行service.unbind()
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
bumpServiceExecutingLocked(s, false, "unbind");
if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
&& s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) {
// If this service's process is not already in the cached list,
// then update it in the LRU list here because this may be causing
// it to go down there and we want it to start out near the top.
mAm.updateLruProcessLocked(s.app, false, null);
}
mAm.updateOomAdjLocked(s.app);
b.intent.hasBound = false;
// Assume the client doesn't want to know about a rebind;
// we will deal with that later if it asks for one.
b.intent.doRebind = false;
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
serviceProcessGoneLocked(s);
}
}
if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
boolean hasAutoCreate = s.hasAutoCreateConnections();
if (!hasAutoCreate) {
if (s.tracker != null) {
s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
}
// 根據(jù)情況決定是否調(diào)用service.onDestroy()方法
bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
}
}
}
scheduleUnbindService()會導(dǎo)致下面的方法在service的主線程中執(zhí)行:
private void handleUnbindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
// 執(zhí)行service.onUnbind()生命周期方法
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
// 如果onUnbind()的返回值設(shè)置為true的話购撼,
// 調(diào)用AMS.unbindFinished()
ActivityManagerNative.getDefault().unbindFinished(
data.token, data.intent, doRebind);
} else {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to unbind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
unbindeService()代碼就說道這里,接下來總結(jié)下:
ServiceConnection.onServiceDisconnected()并不會在unbindeService()過程中調(diào)用谴仙,它只會在service進(jìn)程被終止時(shí)回調(diào)通知綁定的客戶端迂求;
只有在綁定這個(gè)service的所有客戶端中的組件都執(zhí)行了unbindeService()時(shí),service才會被銷毀晃跺,執(zhí)行servcice.onDestroy(),這也就要求暗示我們當(dāng)完成于服務(wù)的交互后揩局,最好unbindeService,這樣有利于系統(tǒng)及時(shí)回收service資源;
當(dāng)目標(biāo)service所在的進(jìn)程被殺掉時(shí)(即除了正诚苹ⅲ回收service)凌盯,系統(tǒng)并不會銷毀之前的與該service綁定的組件創(chuàng)建的連接,一旦service后續(xù)再次運(yùn)行烹玉,系統(tǒng)會再次回調(diào)onServiceConnected()驰怎;
如果service是通過startService()啟動的,那么service將一直運(yùn)行到其通過 stopSelf() 自行停止二打,或其他組件調(diào)用 stopService() 為止县忌,無論其是否綁定到任何客戶端;
unbindeService()操作也是異步操作的继效;
一般情況下症杏,只要service被客戶端綁定過了,當(dāng)其再被綁定時(shí)莲趣,不會在調(diào)用service.onBind()方法了鸳慈,也就是說通常service.onBind()只會執(zhí)行一次;
同一個(gè)組件內(nèi)使用同一個(gè)ServiceConnection接口對象喧伞,重復(fù)綁定一個(gè)service時(shí)走芋,會在AMS中為起創(chuàng)建連接绩郎,但是不會導(dǎo)致ServiceConnection.onServiceConnected()方法執(zhí)行
同一個(gè)組件內(nèi)執(zhí)行unbindeService(ServiceConnection sc)時(shí),相當(dāng)于對所有使用sc綁定的service執(zhí)行一次unbindeService操作翁逞;
這里比較有趣的是肋杖,假設(shè)同一組件內(nèi)使用sc重復(fù)綁定的一個(gè)servcie N次,那么這一次unbindeService(),當(dāng)對于該該組件綁定該service來說執(zhí)行了N次unbindeService操作挖函。
生命周期的總結(jié):
單獨(dú)使用bindService()状植,unbindService()會經(jīng)歷:->onCreate()->onBind()->Service running->onUnbind() -> onDestroy();
單獨(dú)使用startService()怨喘,stopService()會經(jīng)歷:->onCreate()->onStartCommand()->Service running-> onDestroy()津畸;
先調(diào)用startService(),再調(diào)用bindService()方法:
a. 如果結(jié)束只調(diào)用unbindService()必怜,那么只會執(zhí)行到onUnbind()肉拓,將不會執(zhí)行onDestroy():->onCreate()->onStartCommand()->onBind()->Service running-> onUnbind();
b. 如果在unbindService后,在調(diào)用stopService()梳庆,那么:->onCreate()->onStartCommand()->onBind()->Service running-> onUnbind()->onDestroy();
service的生命周期方法都運(yùn)行在主線程中暖途,所以如果要在生命周期中執(zhí)行耗時(shí)操作,請額外開啟線程膏执。