源码分析Android bindService与startService区别
来源:互联网 发布:快手作品制作软件 编辑:程序博客网 时间:2024/06/07 07:02
android启动service,不管是bindService还是startService都不像activity那样复杂,需要创建activity的窗口,pause、resume activity等一系列生命周期操作,简单粗暴直奔ActivityManagerNative.getDefault().startService和bindService, 跟activity一样运用的是著名的binder机制,下面直接在server端,也就是ActivityManagerService直接分析他们的区别。
startservice和bindservice的区别,其中一个就是生命周期的不同
1.通过startservice开启的服务.一旦服务开启, 这个服务和开启他的调用者之间就没有任何的关系了.
调用者不可以访问 service里面的方法. 调用者如果被系统回收了或者调用了ondestroy方法, service还会继续存在
2.通过bindService开启的服务,服务开启之后,调用者和服务之间 还存在着联系 ,
调用者不可以访问 service里面的方法. 调用者如果被系统回收了或者调用了ondestroy方法, service还会继续存在
2.通过bindService开启的服务,服务开启之后,调用者和服务之间 还存在着联系 ,
一旦调用者挂掉了.service也会跟着挂掉 .
我们的问题是如何做到的,我们继续从源码分析。
bindService源码
public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { enforceNotIsolatedCaller("bindService"); // Refuse possible leaked file descriptors if (service != null && service.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } synchronized(this) { return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, userId); } }int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags,int userId) { ...ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); IBinder binder = connection.asBinder(); ArrayList<ConnectionRecord> clist = s.connections.get(binder); if (clist == null) { clist = new ArrayList<ConnectionRecord>(); s.connections.put(binder, clist); } clist.add(c); b.connections.add(c); if (activity != null) { if (activity.connections == null) { activity.connections = new HashSet<ConnectionRecord>(); } activity.connections.add(c); } b.client.connections.add(c); if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) { b.client.hasAboveClient = true; } clist = mServiceConnections.get(binder); if (clist == null) { clist = new ArrayList<ConnectionRecord>(); mServiceConnections.put(binder, clist); } clist.add(c); if ((flags&Context.BIND_AUTO_CREATE) != 0) { s.lastActivity = SystemClock.uptimeMillis(); if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) { return 0; } } ...}
startService源码
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, int userId) { ... return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);}ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) { ... String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false); if (error != null) { return new ComponentName("!!", error); } ...}
从源码上看,不管是bindService,还是startService,最后都调了bringUpServiceLocked,不同的是bindService之前会创建一个ConnnectionRecord对象,并保存到ConnectionRecord ArrayList中,还有
if (activity != null) { if (activity.connections == null) { activity.connections = new HashSet<ConnectionRecord>(); } activity.connections.add(c); }
添加到ActivityRecord当中。下面我们来看unbindService究竟干了什么。
boolean unbindServiceLocked(IServiceConnection connection) { IBinder binder = connection.asBinder(); if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder); ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder); if (clist == null) { Slog.w(TAG, "Unbind failed: could not find connection for " + connection.asBinder()); return false; } final long origId = Binder.clearCallingIdentity(); try { while (clist.size() > 0) { ConnectionRecord r = clist.get(0); removeConnectionLocked(r, null, null); if (r.binding.service.app != null) { // This could have made the service less important. mAm.updateOomAdjLocked(r.binding.service.app); } } } finally { Binder.restoreCallingIdentity(origId); } return true; }
从取出对应的ConnectionRecord,然后调用removeConnectionLock,从代码上看,只是remove ConnectionRecord,跟activity生命周期没有关系,我们要找的不在这里。我们再从Activity结束来分析,Activity的生命周期主要是由ActivityStack来控制,我们发现Activity有个私有对象是mPausingActivity,activity onDestroy 时肯定会调到destroyActivityLocked。
final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, boolean oomAdj, String reason) { ...}final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) { …}finalvoid cleanUpActivityServicesLocked(ActivityRecord r) { // Throw away any services that have been bound by this activity. if (r.connections != null) { Iterator<ConnectionRecord> it = r.connections.iterator(); while (it.hasNext()) { ConnectionRecord c = it.next(); mService.mServices.removeConnectionLocked(c, null, r); } r.connections = null; } }
最终,我们找到了,在ActivityStack cleanUpActivityServicesLocked方法中找到了答案,在activity结束之前会遍历,看是否还是ConnectionRecord,如果有,就结束它,也就解释了为什么bindService生命周期与调用者同步。
1 0
- 源码分析Android bindService与startService区别
- Android 5.0源码分析---startService与bindService的区别
- android startService bindService区别
- android startService 与bindService的区别
- android service startService与bindService的区别
- Android之startService与bindService的区别
- android-startService与bindService
- startService与bindService的区别
- startService与bindService的区别
- startService 与 bindService的区别
- startService与bindService的区别
- startService与bindService的区别
- startService与bindService的区别
- startService与bindService的区别
- startService与bindService的区别
- startService与bindService的区别
- startService与bindService的区别
- startService与bindService的区别
- css1.16
- Error:(54, 84) 警告: 最后一个参数使用了不准确的变量类型的 varargs 方法的非 varargs 调用;
- Spring 自定义属性编辑(CustomEditorConfigurer)和类型转换器(ConversionServiceFactoryBean)一起配置问题
- learnR_function_1
- html5学习笔记(三)
- 源码分析Android bindService与startService区别
- 基于ubuntu 16.10内核编程环境搭建
- css1.17
- git学习总结
- 每天一个linux命令:ps命令
- OpenGL---三维世界中摄像机的构建
- SPSS23mac版本序列号共享
- 前端切图
- WEBSOCKET本地测试正常,上传到云服务器报404可能出现的问题