跨进程通信AIDL的学习

一.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里面声明服务

<service
android: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() {
@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;//回收资源
}

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

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;
    }
};
@Override
public 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;//回收资源
    }
};
@Override
protected 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);//第二个参数是绑定服务时的回调,第三个参数是一个标志
}
@Override
protected 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"));

就成功了。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值