Android进阶笔记:bindService的流程–源码解析
第一次写博客,目的也是为了记录自己在Android学习过程中自己发现的一些值得学习反复琢磨的东西也希望能和大家一起分享,如果写的有什么不对的地方还请大家多多指点。
首先想要知道bindService这一过程是怎么样实现的,得先找到个路口,这个路口也很明显,就是Activity中的bindService方法。代码如下:
bindService(serviceIntent,serviceConnection, Service.BIND_AUTO_CREATE);
参数很简单都很简单,用过的应该都了解。第一个参数就是一个启动service的Intent而第二个参数是一个ServiceConnection的对象。这个对象的实现一般需要实现两个接口,如下所示:
ServiceConnection serviceInatent = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
实现的方法中会返回两个参数一个是ComponentName 另外一个是IBinder类型的实例。这个ComponentName其实就是记录一个应用的包名已经相关的组件名(例如:包名”com.android.myservice”,组件名”com.android.myservice”),而这个IBinder类型的对象就是Service中OnBind方法中返回的Binder对象,如下:
public IBinder onBind(Intent intent) {
return null;
}
具体这中间到底怎么实现的我们还是来看看源码吧。Ctrl按住点击bindService方法看到的代码如下:
public class ContextWrapper extends Context {
...
Context mBase;
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
...
}
这里很清楚直接就就调用了Context的bindService那就直接点进去呗。然后你会看到如下:
public abstract boolean bindService(Intent service, @NonNull ServiceConnection conn,
@BindServiceFlags int flags);
反正我自己一开看的时候就蒙了,这是一个abstract的方法,意思就是真正实现其实在他的子类。这这这。。这你让我去哪里看怎么实现bindService过程,还能不能看代码了?
其实,看到这里你应该就要往回想想,这个方法是刚刚的mBase对象调用的,那这个mBase对象一定就是已经实现了这个方法的子类对象,那我们只要知道这个mBase到底是啥就可以看到这个bindService方法真正实现的过程了。这里直接给出答案这个mBase其实就是ContextImpl类的对象,你要问我咋知道的。很简单这个mBase既然是Activity对象的内部成员,那只要了解Activity创建的过程肯定就知道这是什么了。(具体想知道可以查查Activity创建启动这块的资料,当然我以后也可能会写的哈哈)。
上面写了这么多其实也是为了提供了一个看源码的思路,当然我也是可以直接就告诉你这个方法在哪实现。但是这样就失去了一种过程感,感觉就是在灌输东西死记硬背。有一些东西你“知其所以然”以后印象肯定就非常的深了(这个也是写给我自己的“知其然并且知其所以然”,这也是我开始看源码的目的。我又忍不住废话多了,骚瑞。。。)。
好了继续上面的过程,既然我们知道这个bindService方法具体在哪个类里面实现的我就直接去找到它点进去看看就是了
位置:platform\frameworks\base\core\java\android\app\ContextImpl.java
// bindService
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
// bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, UserHandle user) {
IServiceConnection sd;
...
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
...
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
...
}
这里已经把一些不太重要的代码省略了,首先进入bindService方法,然后直接进入了bindServiceCommon方法当中。而这个bindServiceCommon主要是实现了两个步骤,第一个是实现了一个叫做IServiceConnection的对象,如果有看过一些源码的应该知道就这尿性这命名多半是一个IBinder类的子类。这里我们先“存档”一下,记住等下要回来的!!!千万别绕着绕着就忘记刚刚是从哪绕进来的了(这应该也算是这个方法吧,源码毕竟很多,很容易就看到后面忘记前面了)。
这里首先我们要去看mPackageInfo.getServiceDispatcher这个方法,mPackageInfo这个很简单(看一下声明就知道了)是一个LoadedApk类的实现对象,那么我们就去找到这个对象咯。
位置:platform\frameworks\base\core\java\android\app\LoadedApk.java
public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
找到getServiceDispatcher方法可以看到其实上面一坨都是判断一下是不是空啊,是不是要创建一下啊,是不是要保存一下啦,都是浮云。重要的是最后sd(LoadedApk.ServiceDispatcher)对象调用了getIServiceConnection()这个方法。那我们继续跟踪一下看看这个方法的实现。
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
这个方法是属于Load