AIDL: android interface definition language 安卓接口定义语言 作用:可以调用另一个工程中的方法
在Service总结里面使用绑定服务的方法暴露了MyBind里面的方法
为了不暴露服务类中发方法,就需要一个中间人去调用服务里的方法,而我们就只需要这个中间人的对象,代码如下:
public class MyService extends Service {
private class MyBind extends Binder implements InServiceBinder{
private void method(){
System.out.println("我是服务里面的方法");
}
@Override
public void inMethod() {
method();
}
}
@Override
public IBinder onBind(Intent intent) {
return new MyBind();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
接口的定义:
public interface InServiceBinder {
public void inMethod();
}
调用服务:
public class MainActivity extends Activity implements OnClickListener {
public InServiceBinder binder;//调用服务方法的对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bind=(Button) findViewById(R.id.bind);
Button unbind=(Button) findViewById(R.id.unbind);
Button method=(Button) findViewById(R.id.method);
bind.setOnClickListener(this);
unbind.setOnClickListener(this);
method.setOnClickListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);//避免了退出程序时因为没有取消绑定而程序报错
}
public ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("杀死进程时调用");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("连接了服务");
binder = (InServiceBinder) service;//转换成接口对象,去调用该接口的方法,service对象就是MyBind返回的对象
}
};
@Override
public void onClick(View v) {
Intent intent=new Intent(this,MyService.class);
switch (v.getId()) {
case R.id.bind://绑定服务
bindService(intent, conn, BIND_AUTO_CREATE);
break;
case R.id.unbind://解除绑定
unbindService(conn);
break;
case R.id.method://调用服务里的方法
binder.inMethod();//这样就没有暴露MyService里的方法,而是通过接口来调用MyService里的方法
break;
}
}
}
如果把MyBind类改为public,那么在Activity里面可以通MyBind对象调用该类的所有方法,可是通常我们不想把所有方法都暴露出来,或者不想暴露具体实现的步骤,就可以通过定义接口来实现这样的功能,该接口也就相当于中间人的作用,这样使得MyService类中的方法没有暴露出来,在上面的代码中还有一个问题,就是在解除绑定后还能调用服务中的方法,所以可以在解除绑定的时候把bind对象赋值为null并在使用时进行判断就可以了.
前面说的为本地服务,下面介绍远程服务
远程服务:调用者和服务在不同的工程代码里面。
本地服务:调用者和服务在同一个工程代码里面。
进程间进行通讯都是需要一块公共的空间的
绑定本地服务调用方法的步骤:
1.在服务的内部创建一个内部类 提供一个方法,可以间接调用服务的方法
private class MiddlePerson extends Binder implements IMiddlePerson{}
2.实现服务的onbind方法,返回的就是中间人 MiddlePerson
3.在activity 绑定服务。bindService();
4.在服务成功绑定的时候 会执行一个方法 onServiceConnected 传递过来一个 IBinder对象
5.强制类型转化 调用接口里面的方法。
绑定远程服务调用方法的步骤:
1.在服务的内部创建一个内部类 提供一个方法,可以间接调用服务的方法
2.把暴露的接口文件的扩展名改为aidl文件 去掉访问修饰符 public
private class MiddlePerson extends IMiddlePerson.Stub{} IPC的子类
3.实现服务的onbind方法,返回的就是中间人 IMiddlePerson
4.在activity 绑定服务。bindService();
5.在服务成功绑定的时候 会执行一个方法 onServiceConnected 传递过来一个 IBinder对象
6.IMiddlePerson.Stub.asInterface(binder) 调用接口里面的方法。
aidl文件都是公有的,没有访问权限修饰符
IPC: inter process communication 进程间通讯,在生成的类中里面就是利用了IPC实现两个工程的通讯
上面的那个例子是在自己的工程中创建一个服务,称为本地服务
具体实现两个工程通讯的代码:
1.先创建远程服务工程:在远程工程中创建一个服务
/*
定义远程服务的关键:
1.创建一个接口作为中间人,然后修改该接口的类型为.aidl文件,系统并会在gen目录中自动生成这个类,该类就是实现远程通信的关键
2.在另一个程序中需要创建一个和这个服务同包名,同一个aidl文件
3.在注册服务的时候需要定义一个action,这样才可以在不同的工程中绑定该服务
*/
public class RemoteService extends Service {
private class RemoteBind extends InRemote.Stub{
private void method(){
System.out.println("远程服务中的方法");
}
@Override
public void InRemotemethod() {
method();
}
}
@Override
public IBinder onBind(Intent intent) {
return new RemoteBind();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
说明:InRemote.Stub的Stub为自定生成的类,那么怎么生成的?按照第一个例子创建接口,然后修改扩展名为.aidl文件
InRemote.aidl文件:
package com.example.ts.yuanc;
interface InRemote {
/**
* 远程服务的接口方法
*/
void InRemotemethod();
}
AndroidManifest.xml文件中注册服务
<service android:name=".RemoteService">
<intent-filter >
<action android:name="com.ts.remoteService"/> //为了别的工程也能绑定该服务
</intent-filter>
</service>
2.创建一个工程去绑定上面这个工程中的服务:
1.首先需要在该工程中创建一个与上面.aidl同名同包名同内容的文件 (复制上面的就是)
2.绑定远程服务:
public class MainActivity extends Activity implements OnClickListener {
public InRemote binder;//远程服务通讯的对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bind=(Button) findViewById(R.id.bind);
Button unbind=(Button) findViewById(R.id.unbind);
Button method=(Button) findViewById(R.id.method);
bind.setOnClickListener(this);
unbind.setOnClickListener(this);
method.setOnClickListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);//避免了退出程序时因为没有取消绑定而程序报错
}
public ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("杀死进程时调用");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("连接了服务");
binder=InRemote.Stub.asInterface(service);//得到远程服务的中间人对象
}
};
@Override
public void onClick(View v) {
Intent intent=new Intent();
intent.setAction("com.ts.remoteService");//指定开启远程服务
switch (v.getId()) {
case R.id.bind://绑定服务
bindService(intent, conn, BIND_AUTO_CREATE);
break;
case R.id.unbind://解除绑定
unbindService(conn);
break;
case R.id.method://调用远程服务里的方法
try {
binder.InRemotemethod();//调用远程服务中的方法
break;
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
如果是使用studio实现:可以在module项目上直接右键添加aidl文件
跨进程不同应用之间的通信2-Messenger(信使)实现的:
服务端(注册了服务的)代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
上面只是用来显示个界面而已,下面看服务类:MyService
public class MyService extends Service {
private final int service_message=0;
private final int client_message=1;
/**
* messenger(信使)处理进程的通讯,handler处理线程的通信
* 声名一个服务端的Meesnger用来接收客服端的跨进程消息,通过 handler去处理消息
*/
public Messenger serviceMessenger=new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case client_message://代表接收到的为客服端消息
int arg1 = msg.arg1;
Log.i("tag","获取到客服端的数据:"+arg1);
Messenger clientMessenger = msg.replyTo;//获取客服端对象
Message message = Message.obtain();
message.what=service_message;//代表这是服务端发过去的
message.arg1=100;//发送的数据
try {
clientMessenger.send(message);//利用客服端对象发送消息到客服端的handler
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
});
@Override
public IBinder onBind(Intent intent) {
return serviceMessenger.getBinder();
}
}
注册信息:
<service
android:name=".MyService" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="com.messenger.service"/>
</intent-filter>
</service>
客服端类:用来绑定上面的服务来实现数据之间的传递:
/**
* 利用Messenger(信使)在进程中通信的原理:
* 在客服端绑定服务,连接服务成功就能得到服务端的Messenger对象,就能利用这个对象发送数据给服务端
* 注意:在发送数据给服务端的时候需要携带自己客服端的Messenger对象,这样服务端才能拿到这个对象发送数据给客服端
* 也就是Messenger处理进程的通信,各自的handler再进行处理
*/
public class MainActivity extends AppCompatActivity {
private final int service_message=0;
private final int client_message=1;
private Messenger clientMessenger=new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case service_message://接收到服务端的消息
Log.i("tag","接收到服务端的消息:"+msg.arg1);
break;
}
}
});
private ServiceConnection serviceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//service为服务端的serviceMessenger.getBinder()
Messenger serviceMessenger = new Messenger(service);//获取服务端的Messenger对象
Message message = Message.obtain();
message.what=client_message;//代表是客服端发过去的
message.arg1=1;//向服务端发送数据1
//需要携带客户端的 Messenger,这样服务端才能通过msg获取客服端对象发送消息
message.replyTo = clientMessenger;//切记要给个回应,服务那边才能收到这个对象
try {
serviceMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent=new Intent();
intent.setAction("com.messenger.service");
bindService(intent,serviceConnection,BIND_AUTO_CREATE);//绑定另一个程序的服务
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);//取消绑定,不然退出时会有异常
}
}
总结:Messenger其实是封装了一下AIDL
1. Messenger本质也是AIDL,只是进行了封装,开发的时候不用再写.aidl文件。
结合我自身的使用,因为不用去写.aidl文件,相比起来,Messenger使用起来十分简单。但前面也说了,Messenger本质上也是AIDL,故在底层进程间通信这一块,两者的效率应该是一样的。
2. 在service端,Messenger处理client端的请求是单线程的,而AIDL是多线程的。
使用AIDL的时候,service端每收到一个client端的请求时,就会启动一个线程(非主线程)去执行相应的操作。而Messenger,service收到的请求是放在Handler的MessageQueue里面,Handler大家都用过,它需要绑定一个Thread,然后不断poll message执行相关操作,这个过程是同步执行的。
3. client的方法,使用AIDL获取返回值是同步的,而Messenger是异步的。
Messenger只提供了一个方法进行进程间通信,就是send(Message msg)方法,发送的是一个Message,没有返回值,要拿到返回值,需要把client的Messenger作为msg.replyTo参数传递过去,service端处理完之后,在调用客户端的Messenger的send(Message msg)方法把返回值传递回client,这个过程是异步的,而AIDL你可以自己指定方法,指定返回值,它获取返回值是同步的。