AIDL解析(一)两个应用之间使用AIDL进行通信的例子
2017-03-02 21:41
549 查看
IPC(Inter-Process Communication) :指进程间通信 ,指至少两个进程或线程间传送数据或信号的一些技术或方法
桌面应用Launcher是用Binder IPC启动应用,而进程与进程之间的交流,就是使用AIDL了。不单单是进程与进程之间可以用AIDL,Service和组件之间不但可以用Messenger来通信,也可以用AIDL来通信。使用Messenger更简单,核心是使用Message和Handler来进行线程间的访问,缺点是它是串行的,不能够并发操作,而且也不能跨进程。使用AIDL更为复杂,但是它可以进行并发操作,也可以跨进程。我们要根据实际情况进行选择。
下面是一个两个应用之间通过AIDL来交互的例子
新建两个工程,一个是 Client,负责发送消息。一个是Server,负责接收消息。
![](http://img.blog.csdn.net/20170302220734244)
![](http://img.blog.csdn.net/20170302221137750)
此时项目的机构如下:
![](http://img.blog.csdn.net/20170302221708718)
![](http://img.blog.csdn.net/20170302222809006)
![](http://img.blog.csdn.net/20170302223039426)
完成,在Client点击发送消息,在Server就可以收到消息了:
![](http://img.blog.csdn.net/20170302223649257)
![](http://img.blog.csdn.net/20170302223750929)
总结:A应用去绑定B应用的service ,B应用的service被绑定之后会返回一个Binder对象,A应用通过这个Binder对象向B应用发送消息,B应用的service接收消息并做处理。这和四大组件中的service和activity通信的方法有异曲同工之处,只不过Binder对象换成了MessageCenter.Stub。
参考文章:
Android:学习AIDL,这一篇文章就够了(上)
Android Studio AIDL 自定义类型找不到问题
项目地址:两个应用之间使用AIDL进行通信的例子
桌面应用Launcher是用Binder IPC启动应用,而进程与进程之间的交流,就是使用AIDL了。不单单是进程与进程之间可以用AIDL,Service和组件之间不但可以用Messenger来通信,也可以用AIDL来通信。使用Messenger更简单,核心是使用Message和Handler来进行线程间的访问,缺点是它是串行的,不能够并发操作,而且也不能跨进程。使用AIDL更为复杂,但是它可以进行并发操作,也可以跨进程。我们要根据实际情况进行选择。
下面是一个两个应用之间通过AIDL来交互的例子
新建两个工程,一个是 Client,负责发送消息。一个是Server,负责接收消息。
搭建Client项目
Client的界面如下,可以在输入框输入内容,然后点击按钮发送给Server<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="150dp"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="200dp" android:text="Send"/> </RelativeLayout>
1 新建一个AIDL文件,名字为MessageCenter,程序会帮我们生成一个目录
2 创建一个可以序列化的对象,用来做进程间传输的数据
新建一个java类,叫做Info,并实现Parcelable接口,根据Android Studio的修复完成一部份工作。此时只能由Client传数据到Server端,如果要Server端也能传数据到Client端,还需要加上readFromParcel() 方法。具体代码如下:package com.viii.aidlclient; import android.os.Parcel; import android.os.Parcelable; public class Info implements Parcelable { private String content; public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Info() { } public Info(Parcel in) { content = in.readString(); } public static final Creator<Info> CREATOR = new Creator<Info>() { @Override public Info createFromParcel(Parcel in) { return new Info(in); } @Override public Info[] newArray(int size) { return new Info[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(content); } /** * 参数是一个Parcel,用它来存储与传输数据 * * @param dest */ public void readFromParcel(Parcel dest) { //注意,此处的读值顺序应当是和writeToParcel()方法中一致的 content = dest.readString(); } //方便打印数据 @Override public String toString() { return "content : " + content; } }
3 新建Info.aldl文件
package com.viii.aidlclient; //注意:Info.Info.java的包名应当是一样的 //这个文件的作用是引入了一个序列化对象 Info 供其他的AIDL文件使用 //注意parcelable是小写 parcelable Info;
4 完善MessageCenter.aidl文件内容
package com.viii.aidlclient; //作用是定义方法接口 //导入所需要使用的非默认支持数据类型的包 import com.viii.aidlclient.Info; interface MessageCenter { //所有的返回值前都不需要加任何东西,不管是什么数据类型 List<Info> getInfo(); //传参时除了Java基本类型以及String,CharSequence之外的类型 //都需要在前面加上定向tag,具体加什么量需而定 void addInfo(inout Info info); }
此时项目的机构如下:
5 要让gradle来识别出java包以外的java文件,还需要在项目的build的文件加上
android { ...... sourceSets { main { manifest.srcFile 'src/main/AndroidManifest.xml' java.srcDirs = ['src/main/java', 'src/main/aidl'] resources.srcDirs = ['src/main/java', 'src/main/aidl'] aidl.srcDirs = ['src/main/aidl'] res.srcDirs = ['src/main/res'] assets.srcDirs = ['src/main/assets'] } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } ... }
6 修改MainActivity内容:
package com.viii.aidlclient; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.Toast; import java.util.List; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private EditText editText; //由AIDL文件生成的Java类 private MessageCenter messageCenter = null; //标志当前与服务端连接状况的布尔值,false为未连接,true为连接中 private boolean mBound = false; //包含Book对象的list private List<Info> mInfoList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editText = (EditText) findViewById(R.id.editText); findViewById(R.id.button).setOnClickListener(this); } /** * 按钮的点击事件,点击之后调用服务端的addBookIn方法 */ public void addMessage(String content) { //如果与服务端的连接处于未连接状态,则尝试连接 if (!mBound) { attemptToBindService(); Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show(); return; } if (messageCenter == null) return; Info info = new Info(); info.setContent(content); try { messageCenter.addInfo(info); Log.e(getLocalClassName(),"客户端:"+ info.toString()); } catch (RemoteException e) { e.printStackTrace(); } } /** * 尝试与服务端建立连接 */ private void attemptToBindService() { Intent intent = new Intent(); intent.setAction("com.vvvv.aidl"); intent.setPackage("com.iiiv.aidlserver"); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStart() { super.onStart(); if (!mBound) { attemptToBindService(); } } @Override protected void onStop() { super.onStop(); if (mBound) { unbindService(mServiceConnection); mBound = false; } } private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(getLocalClassName(), "service connected"); messageCenter = MessageCenter.Stub.asInterface(service); mBound = true; if (messageCenter != null) { try { mInfoList = messageCenter.getInfo(); Log.e(getLocalClassName(), mInfoList.toString()); } catch (RemoteException e) { e.printStackTrace(); } } } @Override public void onServiceDisconnected(ComponentName name) { Log.e(getLocalClassName(), "service disconnected"); mBound = false; } }; @Override public void onClick(View view) { switch (view.getId()) { case R.id.button: String content = editText.getText().toString(); // Log.i(getLocalClassName(), content); addMessage(content); break; } } }
搭建Server项目
Server的界面如下<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:text="text"/> </RelativeLayout>
1 拷贝Client下的aidl目录到Server下面
2 新建一个Service负责接收消息,并在AndroidManifest.xml里面注册Service
package com.iiiv.aidlserver.service; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.support.annotation.Nullable; import android.util.Log; import com.viii.aidlclient.Info; import com.viii.aidlclient.MessageCenter; import java.util.ArrayList; import java.util.List; /** * 服务端的AIDLService.java */ public class AIDLService extends Service { public final String TAG = this.getClass().getSimpleName(); //包含Book对象的list private List<Info> messages = new ArrayList<>(); //由AIDL文件生成的BookManager private final MessageCenter.Stub messageCenter = new MessageCenter.Stub() { @Override public List<Info> getInfo() throws RemoteException { synchronized (this) { Log.e(TAG, "getInfo invoking getInfo() method , now the list is : " + messages.toString()); if (messages != null) { return messages; } return new ArrayList<>(); } } @Override public void addInfo(Info message) throws RemoteException { synchronized (this) { if (messages == null) { messages = new ArrayList<>(); } if (message == null) { Log.e(TAG, "message is null in In"); message = new Info(); } //尝试修改book的参数,主要是为了观察其到客户端的反馈 // message.setContent("dididi"); if (!messages.contains(message)) { messages.add(message); } //打印mBooks列表,观察客户端传过来的值 Log.e(TAG, "客户传来了数据" + messages.toString()); // //打开一个程序的后台服务! // Intent serviceIntent = new Intent(); // //设置一个组件名称 同组件名来启动所需要启动Service // serviceIntent.setComponent(new ComponentName("com.yoursender.driversingle", "com.yoursender.driversingle.service.LocationService")); // startService(serviceIntent); //打开一个程序! // Intent launchIntent = getPackageManager().getLaunchIntentForPackage("com.tencent.mobileqq"); // startActivity(launchIntent); } } }; @Override public void onCreate() { Info message = new Info(); message.setContent("消息"); messages.add(message); super.onCreate(); } @Nullable @Override public IBinder onBind(Intent intent) { Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString())); return messageCenter; } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.iiiv.aidlserver"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <service android:name=".service.AIDLService" android:exported="true"> <intent-filter> <action android:name="com.vvvv.aidl"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service> </application> </manifest>
3 修改MainActivity
package com.iiiv.aidlserver; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); } }
4 要让gradle来识别出java包以外的java文件,还需要在项目的build的文件加上
android { ...... sourceSets { main { manifest.srcFile 'src/main/AndroidManifest.xml' java.srcDirs = ['src/main/java', 'src/main/aidl'] resources.srcDirs = ['src/main/java', 'src/main/aidl'] aidl.srcDirs = ['src/main/aidl'] res.srcDirs = ['src/main/res'] assets.srcDirs = ['src/main/assets'] } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } ... }
完成,在Client点击发送消息,在Server就可以收到消息了:
总结:A应用去绑定B应用的service ,B应用的service被绑定之后会返回一个Binder对象,A应用通过这个Binder对象向B应用发送消息,B应用的service接收消息并做处理。这和四大组件中的service和activity通信的方法有异曲同工之处,只不过Binder对象换成了MessageCenter.Stub。
参考文章:
Android:学习AIDL,这一篇文章就够了(上)
Android Studio AIDL 自定义类型找不到问题
项目地址:两个应用之间使用AIDL进行通信的例子
相关文章推荐
- 应用之间的通信Aidl和共享内存块MemoryFile的使用
- socket上http协议应用(使用socket进行http通信的例子,准备好报头以后,简单read/write就可以了)
- 使用Intent和Bundle在两个Activity之间进行通信添加上一步按钮实现回退
- Android 使用AIDL实现了两个app之间的通信
- 使用AIDL进行应用间通信
- 安卓跨应用调用Activity,Service并进行通信,AIDL的应用
- Android应用开发教程:两个运行的Activity之间的通信
- 【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 (二) : 引入中间层NotificationCenter
- 使用Messenger进行Activity与Service之间的双向通信
- 使用RSA对C++ 客户端和 PHP 服务端之间通信的数据进行加密
- java使用UDP来进行客户端和服务器端通信的简单例子
- 使用命名管道通过网络在进程之间进行通信(C#)
- 两个Arduino之间进行串口通信出错的原因
- 两个APK之间进行通信
- 线程间无需特别的手段进行通信,因为线程间可以共享数据结构,也就是一个全局变量可以被两个线程同时使用,不过要注意的是线程间需要做好同步。
- android:json解析的两个工具:Gson和Jackson的使用小例子
- 使用AIDL来进行跨进程通信
- AIDL--------应用之间的通信接口
- [Liferay]Portlet 之间使用 PortletSession 进行通信
- java使用UDP来进行客户端和服务器端通信的简单例子