彻底搞懂AIDL,local service和remote service

Android里Service可以分为两种情况,local service和remote service,其中remote service既可以是同个app中的又可以是另外一个app中的。

区分是否local还是remote就看service和activity是不是运行在同一个进程中。默认情况下如果我们没有在manifest中指定service的process。像这样


则Service和Activity会运行在同个进程中的同个线程,即UI主线程,所以不要在service中直接运行耗时操作,否则会阻塞UI界面。我再另外写一篇文章来试验证明

大家都知道不同进程之间是不能相互访问的。如果我们的确要访问呢?Android帮我们想好了办法,Binder和AIDL(Android Interface Definition Language)。Binder是Activity同Service通信必须要使用的,不太了解Binder的同学建议先了解下,而AIDL则不是必须的。在local service中因为activity和service运行在同一个进程中,所以我们可以在service中创建自己的Binder然后实现函数直接把Serveice实体返回给Activity,这样Activity中就可以直接调用service的任意方法。而remote Service我们必须用到进程间通信的方法了,AIDL。AIDL的详解网上有不少教程,但有些描述的比较繁琐,过后我会写一篇文章专门来阐述。

1,local service

其实本质就是service和activity都没有特别制定process属性,所以他们运行在同一个进程中。要注意,此时不管activity还是service的崩溃都会导致整个进程被关闭。local service和activity通信可以自定义Binder类,然后通过onBind函数将自定义类返回,再在自定义类中将Service实体返回给client。这是最简单的方法。


但是这种方式实现的service没法直接移植到remote service中。

2,local service的AIDL访问方式

1)创建aidl文件,

package com.example.zhenghao.zhservice;

interface IZhAidlInterface {
    String getZhString();
}

编译之后会在build目录下产生IZhAidlInterface.java文件,其中包含IZhAidlInterface.stub和IZhAidlInterface.stub.proxy内部类。具体AIDL机制我就不在这里讲了,IZhAidlInterface类和IZhAidlInterface.stub类是我们需要直接打交道的。

2)service中创建自定义类,继承自IZhAidlInterface.stub

public class ZhAidlImpl extends IZhAidlInterface.Stub {

    @Override
    public String getZhString() throws RemoteException {
        return "hello from service via AIDL";
    }
}

3)通过onBind接口将ZhAidlImpl实例返回

    public IBinder onBind(Intent intent) {
        return new ZhAidlImpl();
    }

4)client中定义ServiceConnection类

ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {

        aidl = IZhAidlInterface.Stub.asInterface(service);

        try {
            out.setText(aidl.getZhString());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};
重点讲一下IZhAidlInterface.Stub.asInterface(service);这一句,点进去看一下。

public static com.example.zhenghao.zhservice.IZhAidlInterface asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.example.zhenghao.zhservice.IZhAidlInterface))) {
        return ((com.example.zhenghao.zhservice.IZhAidlInterface) iin);
    }
    return new com.example.zhenghao.zhservice.IZhAidlInterface.Stub.Proxy(obj);
}
obj.queryLocalInterface(DESCRIPTOR)首先检查正在绑定的service是否是本地service,如果是本地service则直接将service中IZhAidlInterface.Stub的实现类对象返回,在本例中就是ZhAidlImpl。如果不是本地service,那么service和client就不是运行在同一个进程中,必须通过进程间通信的方式相互访问。那么会返回IZhAidlInterface.Stub.Proxy。

具体的进程间通信怎么实现的,我们不去了解也不会影响使用。

我们在ServiceConnection的onServiceConnected方法中就可以得到实现了IZhAidlInterface接口的实体。后面就是函数访问的方式来进行进程间通信了。

3, remote service的AIDL访问。

在同一个android项目中我们可以通过设置Manifest文件中的process属性让service运行在独立的进程,也可以是另外一个apk中的service。前面一种情况,我们只需要将上边讲的本地service的AIDL访问中的service做如下修改即可。

<service android:name="service.ZhService"
    android:process=":remote">
    <intent-filter>
        <action android:name="
myService"/>
    </intent-filter>
</service>
我们重点讲解下后面的跨apk的进程间通信。

1)Android Studio项目中再创建一个module,然后将第一个module中编译之后生成的IZhAidlInterface.java拷贝过来。

2)在client中参照上边的例子创建自定义ServiceConnection。

3)通过包名和类名或者Action的方式绑定service。注:很多比较老的教程里会教大家用隐式Intent的方式来绑定service,但是在Android 5.0以后Google已经禁止了隐式Intent的请求方式。

我提供两种显式的请求方式

Intent intent = new Intent();
intent.setPackage("com.example.zhenghao.zhservice");
intent.setAction("myService");

Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.zhenghao.zhservice", "service.ZhService"));
这两种请求方式都是对应上边的service。

后面的通信就跟上边第二个例子讲的一致了。

最后我抛出一个很多人容易混淆的问题,看看大家理解的怎样。我可能会写一篇文章来专门阐述。

1、同个apk中的Activity和Service是否运行在同一个进程中?

2、不同的apk中Activity是否运行在不同进程中?如果是,那么是否有办法让不同apk中的Activity运行在同一个进程中?

3、多进程和多线程的区别?

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值