一.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"));
就成功了。。