目录
AIDL的使用(同一个app中activity与service的通信)
AIDL是什么?
AIDL(Android接口定义语言),可以使用它定义客户端与服务端进程间通信(IPC)的编程接口。在Android系统中,每个进程都运行在一个独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行通信的需求,比较传递数据或任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL可以在一个进程中获取另一个进程的数据和其暴漏出来的方法,从而满足进程间通信的需求。
AIDL
是用于定义服务端和客户端通信接口的一种描述语言,可以拿来生产
IPC
代码,从某种意义上说 AIDL其实就是一个模板,因为在使用过程中,实际起作用的并不是
AIDL
文件,而是据此生产的一个 Interface的实例代码,
AIDL
其实是为了避免我们重复写代码而出现的一个模板。
注意:只有需要在不同应用的客户端通过IPC方式访问服务,并且希望在服务中进行多线程处理时,您才有必要使用AIDL。如果您无需跨不同应用执行并发IPC,则通过实现Binder来创建接口,或者,您如果想执行IPC,但不需要处理多线程,请使用Messenger来实现接口。无论如何,在使用AIDL前请您务必理解解绑业务
使用流程
- 在.aidl文件中定义AIDL接口,并将其添加到应用工程的src目录下,创建完成之后rebuild
- 在Android SDK 工具会自动生成基于该.aidl文件的IBinder接口,具体的业务对象实现这个接口。这个具体的业务对象也是IBinder对象,但绑定服务的时候会根据实际情况返回具体的通信对象(本地还是代理)
- 将客户端绑定到该服务上,之后就可以调用IBinder中的方法来进行进程间通信(IPC)
AIDL的使用(同一个app中activity与service的通信)
- 现在工程的src目录下创建.aidl文件
- 打开生成的aidl文件,在其中添加具体的业务方法如:
// ILoginAidlInterface.aidl package com.shy.myserverwork; // Declare any non-default types here with import statements interface ILoginAidlInterface { //自己添加的业务 void setAccount(String account); void setPwd(String pwd); boolean getInfo(); //自动生成的 /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); }
然后rebuild,Android SDK工具会在相应的目录生成对应的.aidl文件同名的 .java接口文件
-
这个业务需要一个具体的实现类来完成,创建一个类并继承接口下的stud抽象类
package com.shy.payserver; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class PayImpl extends IPayAidlInterface.Stub{ String account; double money; @Override public void setAccount(String account) throws RemoteException { this.account=account; } @Override public void setMoney(double money) throws RemoteException { this.money = money; } @Override public String getInfo() throws RemoteException { return "账号:"+account+"金额:"+money; } @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } } }
创建一个服务Service以便于对外提供具体的业务
public class PayService extends Service { public PayService() { } @Override public IBinder onBind(Intent intent) { return new PayImpl(); }
-
客户端远程调用
//建立连接 Intent intent=new Intent(); intent.setComponent(new bindService(intent,conn,BIND_AUTO_CREATE); //进行通信 iLoginAidlInterface.setAccount(pwd); iLoginAidlInterface.setPwd(account); flag=iLoginAidlInterface.getInfo(); public ServiceConnection conn=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iLoginAidlInterface=ILoginAidlInterface.Stub.asInterface(service); Log.i("TAG", "onServiceConnected: "+iLoginAidlInterface); } @Override public void onServiceDisconnected(ComponentName name) { } };
两个APP进行AIDL通信
- 创建服务端APP
- 创建一个aidl文件只做业务逻辑接口并且rebuild
interface IPayAidlInterface { void setAccount(String account); void setMoney(double money); String getInfo(); /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); }
-
创建一个类实现stub,并完成业务逻辑(我把它作为了service的内部类)
-
将接口暴露出去,使用service
public class PayService extends Service { public PayService() { } @Override public IBinder onBind(Intent intent) { return new PayImpl(); } public class PayImpl extends IPayAidlInterface.Stub{ String account; double money; @Override public void setAccount(String account) throws RemoteException { this.account=account; } @Override public void setMoney(double money) throws RemoteException { Intent intent=new Intent(PayService.this,MainActivity.class); // startActivity(intent); intent.putExtra("name",account); intent.putExtra("money",money); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); this.money = money; } @Override public String getInfo() throws RemoteException { return "账号:"+account+"金额:"+money; } @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } } }
-
创建客户端APP
-
将服务器中的.aidl文件复制到客户端中
-
在Activity中绑定,使用接收到的IBinder进行通信
public class MainActivity extends AppCompatActivity { private ILoginAidlInterface iLoginAidlInterface; public Button btn_login; private TextInputEditText et_account,et_pwd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_login=findViewById(R.id.btn_login); et_account=findViewById(R.id.et_account); et_pwd=findViewById(R.id.et_pwd); Intent intent=new Intent(); intent.setComponent(new ComponentName("com.shy.myserverwork","com.shy.myserverwork.MyBindService")); bindService(intent,conn,BIND_AUTO_CREATE); btn_login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String pwd= et_pwd.getText().toString(); String account= et_account.getText().toString(); boolean flag; try { iLoginAidlInterface.setAccount(pwd); iLoginAidlInterface.setPwd(account); flag=iLoginAidlInterface.getInfo(); if (flag){ }else { Toast.makeText(MainActivity.this, "登陆失败", Toast.LENGTH_SHORT).show(); } } catch (RemoteException e) { e.printStackTrace(); } } }); } public ServiceConnection conn=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iLoginAidlInterface=ILoginAidlInterface.Stub.asInterface(service); Log.i("TAG", "onServiceConnected: "+iLoginAidlInterface); } @Override public void onServiceDisconnected(ComponentName name) { } }; }
注意:如果您的应用以 Android 10(API 级别 29)或更低版本为目标平台,那么全部应用均会自动对您的应用可见。
如果您的应用以 Android 11(API 级别 30)或更高版本为目标平台,并且需要与应用(自动可见的应用除外)交互,请在您应用的清单文件中添加 <queries> 元素。在 <queries> 元素中,按软件包名称、按 intent 签名或按提供程序授权指定其他应用,如以下部分所述。查询特定软件包及与之交互<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.shy.client"> <queries> <package android:name="com.shy.myserverwork"/> </queries> ... </manifest>