Open MoJieBlog opened 5 years ago
上面说的很完整 补充一张图。
1、生命周期上的区别
执行startService时,Service会经历onCreate->onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service会一直在后台运行,下次调用者再起来仍然可以stopService。 执行bindService时,Service会经历onCreate->onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind->onDestroy。这里所谓的绑定在一起就是说两者共存亡了。 多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。 第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind方法并不会被多次调用,即并不会多次创建服务和绑定服务。
2、调用者如何获取绑定后的Service的方法
onBind回调方法将返回给客户端一个IBinder接口实例,IBinder允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。我们需要IBinder对象返回具体的Service对象才能操作,所以说具体的Service对象必须首先实现Binder对象。
3、既使用startService又使用bindService的情况
如果一个Service又被启动又被绑定,则该Service会一直在后台运行。首先不管如何调用,onCreate始终只会调用一次。对应startService调用多少次,Service的onStart方法便会调用多少次。Service的终止,需要unbindService和stopService同时调用才行。不管startService与bindService的调用顺序,如果先调用unbindService,此时服务不会自动终止,再调用stopService之后,服务才会终止;如果先调用stopService,此时服务也不会终止,而再调用unbindService或者之前调用bindService的Context不存在了(如Activity被finish的时候)之后,服务才会自动停止。 那么,什么情况下既使用startService,又使用bindService呢? 如果你只是想要启动一个后台服务长期进行某项任务,那么使用startService便可以了。如果你还想要与正在运行的Service取得联系,那么有两种方法:一种是使用broadcast,另一种是使用bindService。前者的缺点是如果交流较为频繁,容易造成性能上的问题,而后者则没有这些问题。因此,这种情况就需要startService和bindService一起使用了。 另外,如果你的服务只是公开一个远程接口,供连接上的客户端(Android的Service是C/S架构)远程调用执行方法,这个时候你可以不让服务一开始就运行,而只是bindService,这样在第一次bindService的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是远程服务,那么效果会越明显(当然在Servcie创建的是偶会花去一定时间,这点需要注意)。
4、本地服务与远程服务
本地服务依附在主进程上,在一定程度上节约了资源。本地服务因为是在同一进程,因此不需要IPC,也不需要AIDL。相应bindService会方便很多。缺点是主进程被kill后,服务变会终止。 远程服务是独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被kill的是偶,该服务依然在运行。缺点是该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。 对于startService来说,不管是本地服务还是远程服务,我们需要做的工作都一样简单。
在高版本的Android系统中,当主进程被Kill后,应该是整个进程组都会被Kill掉,包括远程服务。之前做进程保活的时候有用过远程服务来实现,但是会被Kill掉。
上面已经说了很多了,这里补充一点:为什么 bindService 能和 Activity 的生命周期联动? 这个需要到ContextImpl里面看下源码:
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser());
}
最终下去会发现给一个LoadedApk里面,里面使用了一个名叫mService的Map将Serivice的信息存储起来了,然后在ActivityThead的handleDestroyActivity方法里面找到下面的代码的:
Context c = r.activity.getBaseContext();
if (c instanceof ContextImpl) {
((ContextImpl) c).scheduleFinalCleanup(
r.activity.getClass().getName(), "Activity");
}
追踪下去就会到H类的处理HanlderMessage里面:
case CLEAN_UP_CONTEXT:
ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
cci.context.performFinalCleanup(cci.who, cci.what);
break;
回到ContextImpl:
final void performFinalCleanup(String who, String what) {
//Log.i(TAG, "Cleanup up context: " + this);
mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
}
回到了LoadedApk,在removeContextRegistrations方法里面有这么一段代码:
synchronized (mServices) {
//Slog.i(TAG, "Receiver registrations: " + mReceivers);
**ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
mServices.remove(context);**
if (smap != null) {
for (int i = 0; i < smap.size(); i++) {
LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
what + " " + who + " has leaked ServiceConnection "
+ sd.getServiceConnection() + " that was originally bound here");
leak.setStackTrace(sd.getLocation().getStackTrace());
Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
if (reportRegistrationLeaks) {
StrictMode.onServiceConnectionLeaked(leak);
}
try {
ActivityManager.getService().unbindService(
sd.getIServiceConnection());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
sd.doForget();
}
}
mUnboundServices.remove(context);
//Slog.i(TAG, "Service registrations: " + mServices);
}
看到这里的吗:
ActivityManager.getService().unbindService(
sd.getIServiceConnection());
总结就是bindService会让系统保存该Service的信息并在ActivtyThread里面监听Actiivty的销毁,通过一个for循环找出需要解除绑定的Serice来进行解绑
上述已经说得很好啦
我这里也来写一遍 加深印象
区别:对应着动态绑定和静态绑定; 静态对应着startService,动态对应着bindService,静态有自己独立的生命周期,动态会依附activity等组件的生命周期。
生命周期: onCreate → startCommand → onDestroy onCreate → onBind→onUnBind→ onDestroy
使用场景:即上述区别,如果需要一直存在的服务,即静态绑定,反之依赖于组件
startService和bindService的区别在于启动方式和生命周期 startService启动的Service的生命周期是onCreate-onStartCommand onDestroy bindService启动的Service的生命周期是onCreate-onbind-unbind onDestroy 使用场景 startService开启后只要不调用stopService就会一直存在 需要长时间在后台的服务使用startService bindService开启后除了unbindService关闭 所绑定的Activity组件关闭后服务也会关闭 需要依赖组件的场景使用bindService
1、生命周期上的区别
2、调用者如何获取绑定后的Service的方法
3、既使用startService又使用bindService的情况
4、本地服务与远程服务