跨进程通信AIDL的学习

来源:互联网 发布:雍熙北伐 知乎 编辑:程序博客网 时间:2024/06/05 11:15

一.AIDL服务(接口定义语言)

通过定义接口的方式实现两个应用的通信,两个应用,一个叫它Service端,另一个叫它Client端.

在使用前要先考虑下有没有必要,因为这种方式比较耗内存,没有必要就尽量不用他,避免可能出现的OOM。
AIDL、Binder IPC、Messenger 都可以实现IPC(进程间通信) 只是AIDL适合多线程,另外两种不支持多线程,即多个程序用到对应的aidl文件。所以不需要多线程的可以不用aidl这种IPC方式

二、总的流程

**Service端需要做的:
1.创建接口
2.创建service 在service中实现接口方法,将接口返回的ibinder对象暴露给客户端使用
3.清单文件中注册并配置service
Client端需要做的:
1.创建和Service端相同的aidl文件,文件夹,包名也都要相同,copy过去即可。
2.bindService
3.通过bindService获得到的接口对象调用方法,最终获得结果(这样的方法也叫接口回调方法)**

三、具体实现步骤

1.生成个aidl文件、里面定义一个接口,Android studio中弄完接口后先编译一下,才能生成Java文件,这样在其他文件里面就有引用提示了(敲几个字母就提示整个接口名)
客户端跟服务端的接口必须一致,包名阿内容阿之类的,可以在服务端连同包一起拷贝aidl文件到客户端
这里写图片描述
就像上面两个module那样
aidl文件里定义接口:

package com.example.jim.demo_all.aidl;//定义一个接口interface My_AidlInterface {    int add(int n1,int n2);//要被调用方法的声明}

2,写一个服务去实现接口(该方式的实现是通过该服务被另一个进程绑定时,返回一个iBinder对象给那个线程,那个对象可以通过ibinder对象调用Service里面的功能函数

public class aidl_Service extends Service{//当客服端绑定到这个服务时就会调用它public IBinder onBind(Intent intent) {    return mBinder;}private final My_AidlInterface.Stub mBinder = new My_AidlInterface.Stub() {    @Override    public int add(int n1, int n2) throws RemoteException {        return n1+n2;    }};public void onCreate() {    super.onCreate();    Log.d("aidl服务开始了", ": ");}

}

manifest里面声明服务

<serviceandroid:name=".aidl_Service"android:exported="true"android:process=":helloaidl">>

4.客户端要去绑定服务端定义的服务

Intent intent=new Intent();intent.setComponent(new ComponentName("com.example.jim.demo_all", "com.example.jim.demo_all.aidl_Service"));

//想要绑定服务的包名跟类名(类名要具体)

bindService(intent,conn, Context.BIND_AUTO_CREATE);//第二个参数是绑定服务时的回调,第三个参数是一个标志

5.拿到返回的ibinder对象

My_AidlInterface my_aidlinterface;private ServiceConnection conn=new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {    my_aidlinterface=My_AidlInterface.Stub.asInterface(service);//拿到远程服务返回的ibinder对象service}@Overridepublic void onServiceDisconnected(ComponentName name) {    my_aidlinterface=null;//回收资源}

};
拿到后就可以通过它调用服务里面实现的方法了,像下面这样直接调用

int sum=my_aidlinterface.add(num1,num2);

6,在服务解绑、活动销毁时记得回收资源

protected void onDestroy() {super.onDestroy();unbindService(conn);}

完整的Service代码:

package com.example.jim.demo_all;import...import com.example.jim.demo_all.aidl.My_AidlInterface;/** * Created by Jim斌 on 2017/7/11. */public class aidl_Service extends Service{@Nullable@Override//当客服端绑定到这个服务时就会调用它public IBinder onBind(Intent intent) {    return mBinder;}private final My_AidlInterface.Stub mBinder = new My_AidlInterface.Stub() {    @Override    public int add(int n1, int n2) throws RemoteException {        return n1+n2;    }};private IBinder iBinder= new My_AidlInterface.Stub() {    @Override    public int add(int n1, int n2) throws RemoteException {        return n1+n2;    }};@Overridepublic void onCreate() {    super.onCreate();    Log.d("aidl服务开始了", ": ");}

}
完整的绑定服务代码:

package com.example.jim.aidlclient;import ...import com.example.jim.demo_all.aidl.My_AidlInterface;public class aidlclient_Activity extends AppCompatActivity  {private EditText n1,n2;private TextView num;private Button add;My_AidlInterface my_aidlinterface;private ServiceConnection conn=new ServiceConnection() {    @Override    public void onServiceConnected(ComponentName name, IBinder service) {        my_aidlinterface=My_AidlInterface.Stub.asInterface(service);//拿到远程服务返回的ibinder对象service    }    @Override    public void onServiceDisconnected(ComponentName name) {        my_aidlinterface=null;//回收资源    }};@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_aidlclient_);    initview();    bindTheService();}private void initview() {    n1= (EditText) findViewById(R.id.n1);    n2= (EditText) findViewById(R.id.n2);    num= (TextView) findViewById(R.id.num);    add= (Button) findViewById(R.id.add);    add.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View v) {            int num1= Integer.parseInt(n1.getText().toString());            int num2= Integer.parseInt(n2.getText().toString());            try {                int sum=my_aidlinterface.add(num1,num2);                Log.d("等于", "onClick: "+sum);            } catch (RemoteException e) {                e.printStackTrace();            }        }    });}private void bindTheService() {    Log.d("lalala", "bindtherservice(): ");    Intent intent=new Intent();    intent.setComponent(new ComponentName            ("com.example.jim.demo_all", "com.example.jim.demo_all.aidl_Service"));    //想要绑定服务的包名跟类名(类名要具体)    bindService(intent,conn, Context.BIND_AUTO_CREATE);//第二个参数是绑定服务时的回调,第三个参数是一个标志}@Overrideprotected void onDestroy() {    super.onDestroy();    unbindService(conn);}

}

四、遇到的坑:

1.一定要记得在服务端manifest里面声明服务啊
2.一直显示绑定不成功,调试的时候看到返回的ibinder对象一直为空,整个流程回想了一次,断点调试了下,范围缩小到绑定服务那里,看论坛博客里遇到的情况都跟我不一样,后来把客户端的那个Service从单独的一个包里提到外面来,然后就莫名绑定成功了…
一开始这样绑定,包名也确定有写对

intent.setComponent(newComponentName("com.example.jim.demo_all.aidl","com.example.jim.demo_all.aidl.aidl_Service"));

就绑定没成功,后来改了一下

intent.setComponent(new ComponentName("com.example.jim.demo_all", "com.example.jim.demo_all.aidl_Service"));

就成功了。。

原创粉丝点击