Android系统编程入门系列之服务Service中的进程间通信

Android系统编程入门系列之服务Service中的进程间通信,第1张

概述在上篇文章以线程间的通信方式Handler类结尾,服务Service还支持的进程间通信,又是具体怎么实现的呢?这就要用到加载服务一文中提到的AIDL语言规范了。 AIDL是 Android Inter

在上篇文章以线程间的通信方式Handler类结尾,服务Service还支持的进程间通信,又是具体怎么实现的呢?这就要用到加载服务一文中提到的AIDL语言规范了。

AIDL是 AndroID Interface DeFinition Language 的缩写,即AndroID接口定义语言,使用其定义的规范编程,可实现AndroID系统上不同进程间的通信。官网ADIL概述中以服务端和客户端通信为例做了大致讲述。与线程间的通信类似,不同进程间的通信也是分为通信消息内容、消息发送方、消息接收方三个部分的,其中的消息内容也就是AIDL支持的数据类型;而由于服务已经位于当前应用程序所在的默认进程,所以服务中所实现的接口内容即对接收消息的处理,也就是消息接收方;相对的,其他需要发送消息的进程都可以看做是客户端进程,只要绑定服务之后都可以调用服务的接口方法,也就是消息发送方。

确定通信的消息内容

在AndroIDStudio中,通信的消息内容以 .aIDl 后缀格式的文件默认保存在开发目录 /src/main/aIDl 下。在 .adil 格式的文件中,编码规则与Java语言一致,其中内容与Java语言中的接口定义类似。
其中支持通信的消息类型分为两类,一类是基本类型,使用基本类型时不需要在文件开头增加导入包名的声明,这些基本类型包括Java语言中的八种基本数据类型,String,CharSequence,List,Map;还有一类是附加类型,除了第一类基本类型,其他在 .java 格式的文件中定义的任何实现android.os.Parcelable接口的类都可以作为附加类型消息传递。附加类型在使用时需要在 .aIDl 文件开头增加导入该类型所在包名的声明。

关于附加类型的定义,以com.java.process.myinterface.Person类型为例。
不仅在 /src/main/java/com/java/process/myinterface 目录下创建 Person.java ,在其中定义Person类并实现Parcelable接口的相关方法。
还要在 /src/main/aIDl/com/java/process/myinterface 目录下创建对应的 Person.aIDl 文件,在其中除了指定包名外,还要声明该类为parcelable接口,示例代码如下

package com.java.process.myinterface;parcelable Person;

.aIDl.java 格式的文件中定义的接口相比有两处不同,其一是无需访问修饰符,其二是对基本数据类型增加数据流向标识符(包括数据流入接收方的in,数据在接收方修改后可流出的out,数据可流向接收方并流出的inout )。

关于通信消息的定义,以com.java.process.myinterface.DataInterface类型为例。
只需要在 /src/main/aIDl/com/java/process/myinterface 目录下创建 DataInterface.aIDl 文件,在其中定义相关接口即可。示例代码如下

package com.java.process.myinterface;import com.java.process.myinterface.Person;interface DataInterface{    voID setVersion(int version);    int getVersion();    voID updatePerson(in Person person);    Person getMainPerson();}

在通信消息定义之后,可以使用AndroIDStudio的编译指令 Build - Make Project 编译当前项目,以使得AndroIDStudio自动生成消息定义的 .java 文件。上文 DataInterface.aIDl 文件在项目编译之后,会在 /build/generated/aIDl_source_output_dir/deBUG/out/com/java/process/myinterface 目录下生成不可编辑的 DataInterface.java 文件,之后即可在项目中通过导包import com.java.process.myinterface.DataInterface;的形式正常使用该接口类了。

通信接收方的服务接收处理

通信接收方就是常说的服务端,通常是自定义的服务Service类,主要负责实现上述通信消息内容的接口,以此接收消息内容并处理。
针对自定义的服务Service类,这里就用到在加载服务文章中提到的绑定服务的生命周期了。重写onBind(Intent intent)方法,在该方法中返回android.os.IBinder类型的对象实例。

而这个IBinder对象是怎么创建的呢?在上文通信消息定义之后自动生成的接口类中,也自动生成了其Stub内部类,在创建该内部类的无参构造方法时,即可自动实现其相关接口方法,继续使用上文示例,这里在服务Service中的接口实现代码如下

package com.java.process.myinterface;import androID.app.Service;import androID.content.Intent;import androID.os.IBinder;import androID.os.Process;import androID.os.remoteexception;import androID.support.annotation.Nullable;import com.java.process.myinterface.DataInterface;public class ProcessService extends Service {    private String versionname;    private Person person;    private final DataInterface.Stub binder=new DataInterface.Stub() {        @OverrIDe        public String getVersionname() throws remoteexception {            //这里可以返回消息versionname给客户端            return versionname;        }        @OverrIDe        public voID setVersionname(String versionname) throws remoteexception {            //这里接收处理来自客户端的消息versionname            ProcessService.this.versionname=versionname;        }        @OverrIDe        public voID updatePerson(Person person) throws remoteexception {            //这里接收处理来自客户端的消息person            ProcessService.this.person.setname(person.getname());            ProcessService.this.person.setAge(person.getAge());        }        @OverrIDe        public Person getMainPerson() throws remoteexception {            //这里可以返回消息person给客户端            return ProcessService.this.person;        }    };    @OverrIDe    public voID onCreate() {        super.onCreate();        versionname="defaultname";        person=new Person();        person.setname("initname");        person.setAge(10);    }    @Nullable    @OverrIDe    public IBinder onBind(Intent intent) {        return binder;    }}
通信发送方的服务绑定

通信发送方就是所谓的客户端了,发送方是与上文中的接收方不在同一个进程的,所以发送方通常需要先绑定接收方的自定义服务Service,也就是在发送方通过上下文环境Context对象调用bindService(Intent service,ServiceConnection conn,int flags)方法,这里的参数在加载服务中已有详细说明。
conn 参数的onServiceConnected(Componentname name,IBinder service)方法中通过调用静态方法(通信消息定义接口的内部类Stub.asInterface(IBinder service)方法)得到通信消息的定义接口的实例化对象。在当前客户端绑定自定义服务Service成功之后,回调该方法,即可将通信消息的定义接口的实例化对象赋值给全局变量使用。
conn 参数的onServicedisconnected(Componentname name)方法中,要记得将全局通信消息定义接口变量的实例化对象置为空,否则在当前客户端与自定义服务Service断开连接后,还调用全局变量的通信消息定义接口的实例化对象的相关方法,可能会出现OOM内存泄露的问题。

最后在需要发送消息的位置,只需要调用全局通信消息定义接口变量的相关方法即可。其中用到的示例代码如下

    private DataInterface dataInterface;    private ServiceConnection conn=new ServiceConnection() {        @OverrIDe        public voID onServiceConnected(Componentname name,IBinder service) {            dataInterface = DataInterface.Stub.asInterface(service);        }        @OverrIDe        public voID onServicedisconnected(Componentname name) {            dataInterface = null;        }    //此处省略对文本编辑控件editText的定义    //该方法在点击editText控件时回调    public voID clickname(VIEw vIEw) {        try {            String setname = editText.getText().toString();            dataInterface.setVersionname(setname);        } catch (remoteexception e) {            e.printstacktrace();        }    }    };
总结

以上是内存溢出为你收集整理的Android系统编程入门系列之服务Service中的进程间通信全部内容,希望文章能够帮你解决Android系统编程入门系列之服务Service中的进程间通信所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1119303.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-29
下一篇 2022-05-29

发表评论

登录后才能评论

评论列表(0条)

保存