哪个网站做免费小程序,建筑信息平台网,为什么建设旅游网站,怎么在百度搜到自己的网站前面两篇文章我们分别总结了Android四种Service的基本使用以及源码层面总结一下startService的执行过程#xff0c;本篇继续从源码层面总结bindService的执行过程。
本文依然按着是什么#xff1f;有什么#xff1f;怎么用#xff1f;啥原理#xff1f;的步骤来分析。
b…前面两篇文章我们分别总结了Android四种Service的基本使用以及源码层面总结一下startService的执行过程本篇继续从源码层面总结bindService的执行过程。
本文依然按着是什么有什么怎么用啥原理的步骤来分析。
bindService使用方法和调用流程都与startService时有很多相似之处方便的话请先阅读上一篇《展开说说Android服务之startService解析》。
是什么
调用bindService()来创建调用方可以通过一个IBinder接口和service进行通信需要通过ServiceConnection建立连接。多用于有交互的场景。
只能调用方通过unbindService()方法来断开连接。调用方可以和Service通讯并且一个service可以同时和多个调用方存在绑定关系解除绑定也需要所有调用全部解除绑定之后系统才会销毁service。 2、有什么
Service和Activity一样也有自己的生命周期也需要在AndroidManifest.xml中注册。另外bindService的使用比startService要复杂一些第一需要中创建一个Binder子类并定义方法来给使用者调用在onBind方法中返回它的实例第二使用者需要创建ServiceConnection对象并在onServiceConnected回调方法调用Binder子类中定义方法。
2.1 在AndroidManifest.xml中注册
和startService注册流程一样 service android:namecom.example.testdemo.service.ServiceJia /
2.2 bindService时Service的生命周期
与startService时执行的生命周期有些不同。
onCreate
它只在Service刚被创建的时刻被调用Service在运行中这个方法将不会被调用。也就是只有经历过onDestroy生命周期以后再次。
onBind
当另一个组件调用 bindService()想要与Service绑定例如执行 RPC时执行在此方法的实现中必须通过返回 IBinder 提供一个接口供客户端用来与服务通信。您必须始终实现此方法但是如果您不想允许绑定则应返回 null。这个方法默认时返回null。
onUnbind
调用方调用 unbindService() 来解除Service绑定时执行。
onDestroy
所有绑定到Service的调用方都解绑以后则系统会销毁该服务。 onRebind
当Service中的onUnbind方法返回true,并且Service调用unbindService之后并没有销毁,此时重新绑定时将会触发onRebind。Service执行过onBind又onUnbind返回true并且还没执行onDestroy等再次bindService就会执行它。 日志打印
bindService2024-12-01 11:19:14.434 30802-30802/com.example.testdemo3 E/com.example.testdemo3.service.ServiceJia: onCreate:
2023-12-01 11:19:14.436 30802-30802/com.example.testdemo3 E/com.example.testdemo3.activity.ServiceActivity: onServiceConnected:
2023-12-01 11:19:14.436 30802-30802/com.example.testdemo3 E/com.example.testdemo3.service.ServiceJia: JiaBinder --doSomething: start conncetion //这里不是生命周期是binder对象调用binder内方法的打印证明完成交互
unbindService2023-12-01 11:21:10.705 12765-12765/com.example.testdemo3 E/com.example.testdemo3.service.ServiceJia: onUnbind:
2023-12-01 11:21:10.705 12765-12765/com.example.testdemo3 E/com.example.testdemo3.service.ServiceJia: onDestroy:
怎么用
因为是有交互的嘛因此肯定比那些启动以后就成了甩手掌柜的startService使用稍微负责一些第一需要中创建一个Binder子类并定义方法来给使用者调用在onBind方法中返回它的实例第二使用者需要创建ServiceConnection对象并在onServiceConnected回调方法调用Binder子类中定义方法。 具体可以参考前面的《展开说说Android四大组件之Service使用》已经总结了使用方法这里不在赘述。 啥原理SDK版本API 30
bindService调用流程都与startService时有很多相似之处方便的话请先阅读上一篇《展开说说Android服务之startService解析》。 bindService的启动方法是调用
Intent serviceIntent new Intent(ServiceActivity.this, ServiceJia.class);
bindService(serviceIntent,serviceConnection, Context.BIND_AUTO_CREATE)
然后我们顺着bindService方法开始解析源码Go
4.1 从ContexWrapper的bindService开始同startService
Override
public boolean bindService(Intent service, ServiceConnection conn,int flags) {return mBase.bindService(service, conn, flags);
}
4.2 ContextImpl类bindService
mBase的类型是Context但实际代码逻辑是在它的实现类ContextImpl类。 Overridepublic boolean bindService(Intent service, ServiceConnection conn, int flags) {warnIfCallingFromSystemProcess();return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,getUser());
}private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,String instanceName, Handler handler, Executor executor, UserHandle user) {// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.IServiceConnection sd;if (conn null) {throw new IllegalArgumentException(connection is null);}if (handler ! null executor ! null) {throw new IllegalArgumentException(Handler and Executor both supplied);}if (mPackageInfo ! null) {if (executor ! null) {sd mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);} else {sd mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);}} else {throw new RuntimeException(Not supported in system context);}validateServiceIntent(service);try {IBinder token getActivityToken();if (token null (flagsBIND_AUTO_CREATE) 0 mPackageInfo ! null mPackageInfo.getApplicationInfo().targetSdkVersion android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {flags | BIND_WAIVE_PRIORITY;}service.prepareToLeaveProcess(this);int res ActivityManager.getService().bindIsolatedService(mMainThread.getApplicationThread(), getActivityToken(), service,service.resolveTypeIfNeeded(getContentResolver()),sd, flags, instanceName, getOpPackageName(), user.getIdentifier());if (res 0) {throw new SecurityException(Not allowed to bind to service service);}return res ! 0;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}bindService调用bindServiceCommon方法。将ServiceConnection 转为Binder的实现类IServiceConnection方便跨进程的远程服务的回调自己定义的方法。
4.3 来到LoadedApk final NonNull LoadedApk mPackageInfo;
因此来到LoadedApk 查看getServiceDispatcher方法
UnsupportedAppUsage
public final IServiceConnection getServiceDispatcher(ServiceConnection c,Context context, Handler handler, int flags) {return getServiceDispatcherCommon(c, context, handler, null, flags);
}private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,Context context, Handler handler, Executor executor, int flags) {synchronized (mServices) {LoadedApk.ServiceDispatcher sd null;ArrayMapServiceConnection, LoadedApk.ServiceDispatcher map mServices.get(context);if (map ! null) {if (DEBUG) Slog.d(TAG, Returning existing dispatcher sd for conn c);sd map.get(c);}if (sd null) {if (executor ! null) {sd new ServiceDispatcher(c, context, executor, flags);} else {sd new ServiceDispatcher(c, context, handler, flags);}if (DEBUG) Slog.d(TAG, Creating new dispatcher sd for conn c);if (map null) {map new ArrayMap();mServices.put(context, map);}map.put(c, sd);} else {sd.validate(context, handler, executor);}return sd.getIServiceConnection();}
}
private final ArrayMapContext, ArrayMapServiceConnection, LoadedApk.ServiceDispatcher mServices new ArrayMap();
mServices记录了应用当前活动的ServiceConnection和ServiceDispatcher的映射关系不知是否记得ActivityThread中也有一个final ArrayMapIBinder, Service mServices new ArrayMap(); 记录了IBinder,和Service的映射关系。
继续说LoadedApk中的service哈上面代码会判断是否存在相同的ServiceConnection如果不存在就创建新ServiceDispatcher实例并将其存储在mService中key时ServiceConnectionvalue为ServiceDispatcherServiceDispatcher内部存储了ServiceConnection和InnerConnection对象。在调用bindService以后Service和调用方成功建立连接时系统会通过InnerConnection调用ServiceConnection中的onServiceConnected方法此时我们就可以利用传过来的IBinder调用Service中的方法完成交互了。这个过程支持跨进程IPC通信比如两个进程使用AIDL通信。 4.4 ContextImpl类bindService的bindIsolatedService
返回头看上面4.2中的bindService方法继续向下看会调用ActivityManagerService的bindIsolatedService方法
synchronized(this) {return mServices.bindServiceLocked(caller, token, service,resolvedType, connection, flags, instanceName, callingPackage, userId);}
4.5 来到ActiveService类的bindServiceLocked
继续调用本类的bringUpServiceLocked
bringUpServiceLocked(serviceRecord, serviceIntent.getFlags(), callerFg, false, false); 在调用本类realStartServiceLocked
realStartServiceLocked(r, app, execInFg); 一般来说源码中当一个方法多次穿梭调用之后突然带上了real那一定是离真相不远了。
app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo), app.getReportedProcState());
这一行就很熟悉了和上一篇startService一样调用的ApplicationThread来创建Service实例并调用它的onCreate生命周期。
上一篇分析这个方法之下是调用onStartCommand生命周期
没错这里也不例外下面requestServiceBindingsLocked(r, execInFg)也会去调用ApplicationThread的scheduleBindService r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.getReportedProcState());
4.6来到ApplicationThread
利用它封装的handler发送BIND_SERVICE消息
public final void scheduleBindService(IBinder token, Intent intent,boolean rebind, int processState) {updateProcessState(processState, false);BindServiceData s new BindServiceData();s.token token;s.intent intent;s.rebind rebind;if (DEBUG_SERVICE)Slog.v(TAG, scheduleBindService token token intent intent uid Binder.getCallingUid() pid Binder.getCallingPid());sendMessage(H.BIND_SERVICE, s);}
接收消息
case BIND_SERVICE:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, serviceBind);handleBindService((BindServiceData)msg.obj);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;
关键来咯 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 {if (!data.rebind) {IBinder binder s.onBind(data.intent);ActivityManager.getService().publishService(data.token, data.intent, binder);} else {s.onRebind(data.intent);ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);}} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}} catch (Exception e) {if (!mInstrumentation.onException(s, e)) {throw new RuntimeException(Unable to bind to service s with data.intent : e.toString(), e);}}}
}
上面代码显示根据token获取Service对象然后判断首次绑定就调用onBind生命周期已经绑定过就调用onReBind生命周期返回的IBinder对象就可以用来调用Service中的方法了。但是为了让调用方拿到这个IBinder就同过onServiceConnected方法回调回去这个工作就有ActivityManagerService的publishService方法来完成。 4.6 来到ActivityManagerService public void publishService(IBinder token, Intent intent, IBinder service) {// Refuse possible leaked file descriptorsif (intent ! null intent.hasFileDescriptors() true) {throw new IllegalArgumentException(File descriptors passed in Intent);}synchronized(this) {if (!(token instanceof ServiceRecord)) {throw new IllegalArgumentException(Invalid service token);}mServices.publishServiceLocked((ServiceRecord)token, intent, service);}}
然后它有调用了ActiveService的publishServiceLocked方法来处理
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {final long origId Binder.clearCallingIdentity();try {if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, PUBLISHING r intent : service);if (r ! null) {Intent.FilterComparison filter new Intent.FilterComparison(intent);IntentBindRecord b r.bindings.get(filter);if (b ! null !b.received) {b.binder service;b.requested true;b.received true;ArrayMapIBinder, ArrayListConnectionRecord connections r.getConnections();for (int conni connections.size() - 1; conni 0; conni--) {ArrayListConnectionRecord clist connections.valueAt(conni);for (int i0; iclist.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 {c.conn.connected(r.name, service, false);} catch (Exception e) {Slog.w(TAG, Failure sending service r.shortInstanceName to connection c.conn.asBinder() (in c.binding.client.processName ), e);}}}}serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);}} finally {Binder.restoreCallingIdentity(origId);}
} 它在for循环里调用一行代码
c.conn.connected(r.name, service, false);
顺着代码看
Conn的类型是是在ConnectionRecord类定义的IServiceConnection
final IServiceConnection conn; // The client connection.
Service就是建立连接的Ibinder实例。
4.7再次来到LoadedApk类
看一下IServiceConnection类connected方法
private static class InnerConnection extends IServiceConnection.Stub {UnsupportedAppUsagefinal WeakReferenceLoadedApk.ServiceDispatcher mDispatcher;InnerConnection(LoadedApk.ServiceDispatcher sd) {mDispatcher new WeakReferenceLoadedApk.ServiceDispatcher(sd);}public void connected(ComponentName name, IBinder service, boolean dead)throws RemoteException {LoadedApk.ServiceDispatcher sd mDispatcher.get();if (sd ! null) {sd.connected(name, service, dead);}}
}
而它又调用了ActivityThread类mActivityThread就是其中Handler子类 H 这一步就是为了利用Handler在主线程回调给调用方的onServiceConnected
public void connected(ComponentName name, IBinder service, boolean dead) {if (mActivityExecutor ! null) {mActivityExecutor.execute(new RunConnection(name, service, 0, dead));} else if (mActivityThread ! null) {mActivityThread.post(new RunConnection(name, service, 0, dead));} else {doConnected(name, service, dead);}
}
RunConnection 的实现
private final class RunConnection implements Runnable {RunConnection(ComponentName name, IBinder service, int command, boolean dead) {mName name;mService service;mCommand command;mDead dead;}public void run() {if (mCommand 0) {doConnected(mName, mService, mDead);} else if (mCommand 1) {doDeath(mName, mService);}}final ComponentName mName;final IBinder mService;final int mCommand;final boolean mDead;
} 回调onServiceConnected彻底呼应上了
public void doConnected(ComponentName name, IBinder service, boolean dead) {ServiceDispatcher.ConnectionInfo old;ServiceDispatcher.ConnectionInfo info;synchronized (this) {if (mForgotten) {// We unbound before receiving the connection; ignore// any connection received.return;}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.info new ConnectionInfo();info.binder service;info.deathMonitor new DeathMonitor(name, service);try {service.linkToDeath(info.deathMonitor, 0);mActiveConnections.put(name, info);} catch (RemoteException e) {// This service was dead before we got it... just// dont 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 now disconnected.if (old ! null) {mConnection.onServiceDisconnected(name);}if (dead) {mConnection.onBindingDied(name);}// If there is a new viable service, it is now connected.if (service ! null) {mConnection.onServiceConnected(name, service);} else {// The binding machinery worked, but the remote returned null from onBind().mConnection.onNullBinding(name);}
} 至此bindService的绑定流程分析完毕
才疏学浅如有错误欢迎指正多谢。