AIDL解析(一)两个应用之间使用AIDL进行通信的例子(有我的注释)

这篇博客有实例代码的,见本地android-study/两个应用之间使用AIDL进行通信的例子

一般来说,aidl支持的数据类型有五种:java基本数据类型;String;CharSequence;List;Map。其中List和Map较为特殊,如果你使用的数据类型不是AIDL的基本数据类型,你必须要使用import语句将其导入,即使他们是在同一个package下。在AIDL机制中Android 会提供一系列工具会将用户定义的*.aidl文件编译生成Client端代码与Service端代码(比如Iwifimanager.aidl 在服务端会生成IWifiManager.Stub ; 在客户端绑定服务端的Ibinder对象(在ServiceManagerRegistry.java中),用户仅仅 需要1)在Service端实现所需要实现的接口。2)在Client端调用相关接口。基于Binder机制,在Clinet端的调用会自动通过binder驱动跨进程到service进程当中。

IPC(Inter-Process Communication) :指进程间通信 ,指至少两个进程或线程间传送数据或信号的一些技术或方法

桌面应用Launcher是用Binder IPC启动应用,而进程与进程之间的交流,就是使用AIDL了。不单单是进程与进程之间可以用AIDL,Service和组件之间不但可以用Messenger来通信,也可以用AIDL来通信。使用Messenger更简单,核心是使用Message和Handler来进行线程间的访问,缺点是它是串行的,不能够并发操作,而且也不能跨进程。使用AIDL更为复杂,但是它可以进行并发操作,也可以跨进程。我们要根据实际情况进行选择。

下面是一个两个应用之间通过AIDL来交互的例子

新建两个工程,一个是 Client,负责发送消息。一个是Server,负责接收消息。

搭建Client项目

Client的界面如下,可以在输入框输入内容,然后点击按钮发送给Server


[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent">  
  6.   
  7.     <EditText  
  8.         android:id="@+id/editText"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="150dp"/>  
  11.     <Button  
  12.         android:id="@+id/button"  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:layout_alignParentTop="true"  
  16.         android:layout_centerHorizontal="true"  
  17.         android:layout_marginTop="200dp"  
  18.         android:text="Send"/>  
  19. </RelativeLayout>  

1  新建一个AIDL文件,名字为MessageCenter,程序会帮我们生成一个目录


2  创建一个可以序列化的对象,用来做进程间传输的数据

 新建一个java类,叫做Info,并实现Parcelable接口,根据Android  Studio的修复完成一部份工作。此时只能由Client传数据到Server端,如果要Server端也能传数据到Client端,还需要加上readFromParcel() 方法。具体代码如下:

[java]  view plain  copy
  1. package com.viii.aidlclient;  
  2.   
  3. import android.os.Parcel;  
  4. import android.os.Parcelable;  
  5.   
  6. public class Info implements Parcelable {  
  7.   
  8.   
  9.     private String content;  
  10.   
  11.     public String getContent() {  
  12.         return content;  
  13.     }  
  14.   
  15.     public void setContent(String content) {  
  16.         this.content = content;  
  17.     }  
  18.   
  19.     public Info() {  
  20.     }  
  21.   
  22.     public Info(Parcel in) {  
  23.         content = in.readString();  
  24.   
  25.     }  
  26.   
  27.     public static final Creator<Info> CREATOR = new Creator<Info>() {  
  28.         @Override  
  29.         public Info createFromParcel(Parcel in) {  
  30.             return new Info(in);  
  31.         }  
  32.   
  33.         @Override  
  34.         public Info[] newArray(int size) {  
  35.             return new Info[size];  
  36.         }  
  37.     };  
  38.   
  39.     @Override  
  40.     public int describeContents() {  
  41.         return 0;  
  42.     }  
  43.   
  44.     @Override  
  45.     public void writeToParcel(Parcel dest, int flags) {  
  46.         dest.writeString(content);  
  47.   
  48.     }  
  49.   
  50.     /** 
  51.      * 参数是一个Parcel,用它来存储与传输数据 
  52.      * 
  53.      * @param dest 
  54.      */  
  55.     public void readFromParcel(Parcel dest) {  
  56.         //注意,此处的读值顺序应当是和writeToParcel()方法中一致的  
  57.         content = dest.readString();  
  58.   
  59.     }  
  60.   
  61.     //方便打印数据  
  62.     @Override  
  63.     public String toString() {  
  64.         return "content : " + content;  
  65.     }  
  66. }  

3  新建Info.aldl文件
[java]  view plain  copy
  1. package com.viii.aidlclient;  
  2.   
  3. //注意:Info.Info.java的包名应当是一样的  
  4.   
  5. //这个文件的作用是引入了一个序列化对象 Info 供其他的AIDL文件使用  
  6.   
  7. //注意parcelable是小写  
  8. parcelable Info;  

4  完善MessageCenter.aidl文件内容

[java]  view plain  copy
  1. package com.viii.aidlclient;  
  2.   
  3. //作用是定义方法接口  
  4.   
  5. //导入所需要使用的非默认支持数据类型的包  
  6. import com.viii.aidlclient.Info;  
  7.   
  8. interface MessageCenter {  
  9.   
  10.        //所有的返回值前都不需要加任何东西,不管是什么数据类型  
  11.        List<Info> getInfo();  
  12.   
  13.        //传参时除了Java基本类型以及String,CharSequence之外的类型  
  14.        //都需要在前面加上定向tag,具体加什么量需而定  
  15.        void addInfo(inout Info info);  
  16.   
  17. }  

此时项目的机构如下:


5  要让gradle来识别出java包以外的java文件,还需要在项目的build的文件加上
[java]  view plain  copy
  1. android {  
  2. ......    
  3.   sourceSets {  
  4.         main {  
  5.             manifest.srcFile 'src/main/AndroidManifest.xml'  
  6.             java.srcDirs = ['src/main/java''src/main/aidl']  
  7.             resources.srcDirs = ['src/main/java''src/main/aidl']  
  8.             aidl.srcDirs = ['src/main/aidl']  
  9.             res.srcDirs = ['src/main/res']  
  10.             assets.srcDirs = ['src/main/assets']  
  11.         }  
  12.     }  
  13.     buildTypes {  
  14.         release {  
  15.             minifyEnabled false  
  16.             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
  17.         }  
  18.     }  
  19. ...  
  20. }  

6 修改MainActivity内容:

[java]  view plain  copy
  1. package com.viii.aidlclient;  
  2.   
  3. import android.content.ComponentName;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.content.ServiceConnection;  
  7. import android.os.Bundle;  
  8. import android.os.IBinder;  
  9. import android.os.RemoteException;  
  10. import android.support.v7.app.AppCompatActivity;  
  11. import android.util.Log;  
  12. import android.view.View;  
  13. import android.widget.EditText;  
  14. import android.widget.Toast;  
  15.   
  16. import java.util.List;  
  17.   
  18. public class MainActivity extends AppCompatActivity implements View.OnClickListener {  
  19.   
  20.     private EditText editText;  
  21.   
  22.     //由AIDL文件生成的Java类  
  23.     private MessageCenter messageCenter = null;  
  24.   
  25.     //标志当前与服务端连接状况的布尔值,false为未连接,true为连接中  
  26.     private boolean mBound = false;  
  27.   
  28.     //包含Book对象的list  
  29.     private List<Info> mInfoList;  
  30.   
  31.     @Override  
  32.     protected void onCreate(Bundle savedInstanceState) {  
  33.         super.onCreate(savedInstanceState);  
  34.         setContentView(R.layout.activity_main);  
  35.         editText = (EditText) findViewById(R.id.editText);  
  36.         findViewById(R.id.button).setOnClickListener(this);  
  37.     }  
  38.     /** 
  39.      * 按钮的点击事件,点击之后调用服务端的addBookIn方法 
  40.      */  
  41.     public void addMessage(String content) {  
  42.         //如果与服务端的连接处于未连接状态,则尝试连接  
  43.         if (!mBound) {  
  44.             attemptToBindService();  
  45.             Toast.makeText(this"当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show();  
  46.             return;  
  47.         }  
  48.         if (messageCenter == nullreturn;  
  49.   
  50.         Info info = new Info();  
  51.         info.setContent(content);  
  52.         try {  
  53.             messageCenter.addInfo(info);  
  54.             Log.e(getLocalClassName(),"客户端:"+ info.toString());  
  55.         } catch (RemoteException e) {  
  56.             e.printStackTrace();  
  57.         }  
  58.     }  
  59.   
  60.     /** 
  61.      * 尝试与服务端建立连接 
  62.      */  
  63.     private void attemptToBindService() {  
  64.         Intent intent = new Intent();  
  65.         intent.setAction("com.vvvv.aidl");  
  66.         intent.setPackage("com.iiiv.aidlserver");  
  67.         bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);  
  68.     }  
  69.   
  70.     @Override  
  71.     protected void onStart() {  
  72.         super.onStart();  
  73.         if (!mBound) {  
  74.             attemptToBindService();  
  75.         }  
  76.     }  
  77.   
  78.     @Override  
  79.     protected void onStop() {  
  80.         super.onStop();  
  81.         if (mBound) {  
  82.             unbindService(mServiceConnection);  
  83.             mBound = false;  
  84.         }  
  85.     }  
  86.   
  87.     private ServiceConnection mServiceConnection = new ServiceConnection() {  
  88.         @Override  
  89.         public void onServiceConnected(ComponentName name, IBinder service) {  
  90.             Log.e(getLocalClassName(), "service connected");  
  91.             messageCenter = MessageCenter.Stub.asInterface(service);  
  92.             mBound = true;  
  93.   
  94.             if (messageCenter != null) {  
  95.                 try {  
  96.                     mInfoList = messageCenter.getInfo();  
  97.                     Log.e(getLocalClassName(), mInfoList.toString());  
  98.                 } catch (RemoteException e) {  
  99.                     e.printStackTrace();  
  100.                 }  
  101.             }  
  102.         }  
  103.   
  104.         @Override  
  105.         public void onServiceDisconnected(ComponentName name) {  
  106.             Log.e(getLocalClassName(), "service disconnected");  
  107.             mBound = false;  
  108.         }  
  109.     };  
  110.   
  111.     @Override  
  112.     public void onClick(View view) {  
  113.         switch (view.getId()) {  
  114.             case R.id.button:  
  115.                 String content = editText.getText().toString();  
  116. //                Log.i(getLocalClassName(), content);  
  117.                 addMessage(content);  
  118.                 break;  
  119.         }  
  120.     }  
  121. }  

搭建Server项目

Server的界面如下



[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     >  
  7.   
  8.     <TextView  
  9.         android:id="@+id/textView"  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content"  
  12.         android:layout_margin="10dp"  
  13.         android:text="text"/>  
  14.   
  15. </RelativeLayout>  

1  拷贝Client下的aidl目录到Server下面


2  新建一个Service负责接收消息,并在AndroidManifest.xml里面注册Service
[java]  view plain  copy
  1. package com.iiiv.aidlserver.service;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.IBinder;  
  6. import android.os.RemoteException;  
  7. import android.support.annotation.Nullable;  
  8. import android.util.Log;  
  9.   
  10. import com.viii.aidlclient.Info;  
  11. import com.viii.aidlclient.MessageCenter;  
  12.   
  13.   
  14. import java.util.ArrayList;  
  15. import java.util.List;  
  16.   
  17.   
  18.   
  19. /** 
  20.  * 服务端的AIDLService.java 
  21.  */  
  22. public class AIDLService extends Service {  
  23.   
  24.     public final String TAG = this.getClass().getSimpleName();  
  25.   
  26.     //包含Book对象的list  
  27.     private List<Info> messages = new ArrayList<>();  
  28.   
  29.     //由AIDL文件生成的BookManager  
  30.     private final MessageCenter.Stub messageCenter = new MessageCenter.Stub() {  
  31.         @Override  
  32.         public List<Info> getInfo() throws RemoteException {  
  33.             synchronized (this) {  
  34.                 Log.e(TAG, "getInfo invoking getInfo() method , now the list is : " + messages.toString());  
  35.                 if (messages != null) {  
  36.                     return messages;  
  37.                 }  
  38.                 return new ArrayList<>();  
  39.             }  
  40.         }  
  41.   
  42.   
  43.         @Override  
  44.         public void addInfo(Info message) throws RemoteException {  
  45.             synchronized (this) {  
  46.                 if (messages == null) {  
  47.                     messages = new ArrayList<>();  
  48.                 }  
  49.                 if (message == null) {  
  50.                     Log.e(TAG, "message is null in In");  
  51.                     message = new Info();  
  52.                 }  
  53.                 //尝试修改book的参数,主要是为了观察其到客户端的反馈  
  54. //                message.setContent("dididi");  
  55.                 if (!messages.contains(message)) {  
  56.                     messages.add(message);  
  57.                 }  
  58.                 //打印mBooks列表,观察客户端传过来的值  
  59.                 Log.e(TAG, "客户传来了数据" + messages.toString());  
  60.   
  61. //                //打开一个程序的后台服务!  
  62. //                Intent serviceIntent = new Intent();  
  63. //                //设置一个组件名称  同组件名来启动所需要启动Service  
  64. //                serviceIntent.setComponent(new ComponentName("com.yoursender.driversingle", "com.yoursender.driversingle.service.LocationService"));  
  65. //                startService(serviceIntent);  
  66.   
  67.                 //打开一个程序!  
  68. //                Intent launchIntent = getPackageManager().getLaunchIntentForPackage("com.tencent.mobileqq");  
  69. //                startActivity(launchIntent);  
  70.             }  
  71.         }  
  72.     };  
  73.   
  74.     @Override  
  75.     public void onCreate() {  
  76.   
  77.         Info message = new Info();  
  78.         message.setContent("消息");  
  79.         messages.add(message);  
  80.         super.onCreate();  
  81.     }  
  82.   
  83.     @Nullable  
  84.     @Override  
  85.     public IBinder onBind(Intent intent) {  
  86.         Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString()));  
  87.         return messageCenter;  
  88.     }  
  89. }  


[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.           package="com.iiiv.aidlserver">  
  4.   
  5.     <application  
  6.         android:allowBackup="true"  
  7.         android:icon="@mipmap/ic_launcher"  
  8.         android:label="@string/app_name"  
  9.         android:roundIcon="@mipmap/ic_launcher_round"  
  10.         android:supportsRtl="true"  
  11.         android:theme="@style/AppTheme">  
  12.         <activity android:name=".MainActivity">  
  13.             <intent-filter>  
  14.                 <action android:name="android.intent.action.MAIN"/>  
  15.   
  16.                 <category android:name="android.intent.category.LAUNCHER"/>  
  17.             </intent-filter>  
  18.         </activity>  
  19.   
  20.         <service  
  21.             android:name=".service.AIDLService"  
  22.             android:exported="true">  
  23.             <intent-filter>  
  24.                 <action android:name="com.vvvv.aidl"/>  
  25.                 <category android:name="android.intent.category.DEFAULT"/>  
  26.             </intent-filter>  
  27.         </service>  
  28.     </application>  
  29.   
  30. </manifest>  


3   修改MainActivity
[java]  view plain  copy
  1. package com.iiiv.aidlserver;  
  2.   
  3. import android.os.Bundle;  
  4. import android.support.v7.app.AppCompatActivity;  
  5. import android.widget.TextView;  
  6.   
  7.   
  8.   
  9. public class MainActivity extends AppCompatActivity {  
  10.   
  11.     private TextView textView;  
  12.   
  13.     @Override  
  14.     protected void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.activity_main);  
  17.   
  18.         textView = (TextView) findViewById(R.id.textView);  
  19.     }  
  20. }  

4  要让gradle来识别出java包以外的java文件,还需要在项目的build的文件加上
[java]  view plain  copy
  1. android {  
  2. ......    
  3.   sourceSets {  
  4.         main {  
  5.             manifest.srcFile 'src/main/AndroidManifest.xml'  
  6.             java.srcDirs = ['src/main/java''src/main/aidl']  
  7.             resources.srcDirs = ['src/main/java''src/main/aidl']  
  8.             aidl.srcDirs = ['src/main/aidl']  
  9.             res.srcDirs = ['src/main/res']  
  10.             assets.srcDirs = ['src/main/assets']  
  11.         }  
  12.     }  
  13.     buildTypes {  
  14.         release {  
  15.             minifyEnabled false  
  16.             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
  17.         }  
  18.     }  
  19. ...  
  20. }  

完成,在Client点击发送消息,在Server就可以收到消息了:




总结:A应用去绑定B应用的service ,B应用的service被绑定之后会返回一个Binder对象,A应用通过这个Binder对象向B应用发送消息,B应用的service接收消息并做处理。这和四大组件中的service和activity通信的方法有异曲同工之处,只不过Binder对象换成了MessageCenter.Stub。

参考文章:
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AIDL(Android Interface Definition Language)是一种用于 Android 平台的接口定义语言,它可以帮助不同进程之间的组件进行通信。下面是使用 AIDL 进行进程间通信的步骤: 1.定义 AIDL 接口 首先,在服务端和客户端之间定义一个 AIDL 接口。在 AIDL 文件中,定义需要向客户端公开的方法和参数。 2.实现 AIDL 接口 在服务端中,实现定义的 AIDL 接口,并在 onCreate() 方法中将其注册到系统中。 3.绑定服务端 在客户端中,使用 bindService() 方法绑定服务端。 4.获取 AIDL 接口实例 在客户端中,实现 ServiceConnection 接口,当服务端连接成功时,会回调 onServiceConnected() 方法。在此方法中,可以获取到 AIDL 接口实例。 5.调用 AIDL 接口方法 在客户端中,通过获取到的 AIDL 接口实例,即可调用服务端暴露的方法。 下面是一个简单的示例代码: 服务端: ``` //定义 AIDL 接口 interface IMyAidlInterface { int add(int a, int b); } //实现 AIDL 接口 class MyAidlInterfaceImpl extends IMyAidlInterface.Stub { @Override public int add(int a, int b) throws RemoteException { return a + b; } } //在 onCreate() 方法中注册 AIDL 接口 @Override public void onCreate() { super.onCreate(); Intent intent = new Intent(this, MyAidlInterfaceService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); Log.i(TAG, "MyAidlInterfaceService is created."); } //定义 ServiceConnection 对象,以便在客户端连接时获取 AIDL 接口实例 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); Log.i(TAG, "MyAidlInterfaceService is connected."); } @Override public void onServiceDisconnected(ComponentName name) { mIMyAidlInterface = null; Log.i(TAG, "MyAidlInterfaceService is disconnected."); } }; ``` 客户端: ``` //定义 ServiceConnection 对象 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //获取 AIDL 接口实例 mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); Log.i(TAG, "MyAidlInterfaceService is connected."); } @Override public void onServiceDisconnected(ComponentName name) { mIMyAidlInterface = null; Log.i(TAG, "MyAidlInterfaceService is disconnected."); } }; //使用 bindService() 方法绑定服务端 Intent intent = new Intent(); intent.setComponent(new ComponentName("com.example.myaidlservice", "com.example.myaidlservice.MyAidlInterfaceService")); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); //调用服务端暴露的方法 int result = mIMyAidlInterface.add(1, 2); ``` 希望这个简单的示例可以帮助你了解如何使用 AIDL 进行进程间通信
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值