Android(安卓)studio 下的aidl编程实现Android的夸进程间通信
前言
Android中夸进程间通信方式有很多种方式,比如:aidl,Messenger,文件共享,广播(BroadCast),ContentProvider,Socket(网络通信)。每种方式都有自己的使用场景和优缺点,接下来几篇博客我们一一学习他们是怎么使用的。这篇博客主要是介绍Android studio下实现aidl编程。
AIDL的使用步骤
aidl远程调用传递的参数和返回值支持Java的基本类型(int long booen char byte等)和String,List,Map等。当然也支持一个自定义对象的传递,不过此时就需要做一些特别处理了,后续会介绍aidl传递对象怎么处理。
有关aidl的相关概念这里就不详细解释了,我们来看看在Android Studio下怎么来实现aidl编程的。
服务端
生成aidl文件
新建一个MyAidlDemoServer工程,然后在main目录下右键新建一个aidl目录,然后在该目录下新建一个IMyAidlInterface.aidl文件,代码如下:
// IMyAidlInterface.aidlpackage com.example.xjp.aidla;interface IMyAidlInterface { int add(int arg1, int arg2);}
定义了一个IMyAidlInterface接口,接口里面定义了一个add方法用于计算两个数的和。然后Build当前工程,在app/build/generated/source/aidl/debug目录下会生成一个与IMyAidlInterface.aidl文件同样包名的一个文件,该文件下面自动生成IMyAidlInterface文件,该文件里面自动实现了一些方法用于远程调用,IMyAidlInterface代码如下:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: D:\\WorkPlace\\MyAidlDemoServer\\app\\src\\main\\aidl\\com\\example\\xjp\\aidla * \\IMyAidlInterface.aidl */package com.example.xjp.aidla;public interface IMyAidlInterface extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.xjp.aidla .IMyAidlInterface { private static final java.lang.String DESCRIPTOR = "com.example.xjp.aidla.IMyAidlInterface"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.xjp.aidla.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.example.xjp.aidla.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.example.xjp.aidla.IMyAidlInterface))) { return ((com.example.xjp.aidla.IMyAidlInterface) iin); } return new com.example.xjp.aidla.IMyAidlInterface.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_add: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.xjp.aidla.IMyAidlInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public int add(int arg1, int arg2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(arg1); _data.writeInt(arg2); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } public int add(int arg1, int arg2) throws android.os.RemoteException;}
以上代码都是AS自动生成的,如此一来,开发者更加容易来实现AIDL跨进程间通信。如有对以上代码感兴趣者,可自行学习。
编写远程服务
新建MyServer类实现远程服务代码如下:
public class MyServer extends Service { IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() { public int add(int arg1, int arg2) { return arg1 + arg2; } }; @Override public IBinder onBind(Intent intent) { return mStub; }}
服务代码也很简单,仅仅实现了IMyAidlInterface.Stub类中的 add方法,然后重写了Service的onBind方法。
记得在AndroidManifest.xml中配置MyServer服务,代码如下:
<?xml version="1.0" encoding="utf-8"?><manifest package="com.example.xjp.aidl" xmlns:android="http://schemas.android.com/apk/res/android"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <service android:name="com.example.xjp.aidl.MyServer" android:process=":remote"> <intent-filter> <action android:name="com.xjp.myService"></action> </intent-filter> </service> </application></manifest>
以上代码给当前service设置了 android:process属性为“:remote”,这个属性有两种赋值,一是:”:remote”,一是:”remote”,区别在于字符串前面带有”:”,后面的字符串不一定是remote,开发者可以随意设置。
两者代表不同意思,带有”:”的表示该服务所在的进程是私有的,即只要有客户端去启动该服务,系统就会创建一个新的进程来运行该服务。
不带有”:”的表示该服务所在的进程是共享的,即当前系统不管有几个客户端去启动该服务,系统中只有一个进程来运行该服务。
客户端
客户端代码相对简单些,新建MyAidlDemoCustomer工程,然后直接把服务端的aidl目录直接拷贝到客户端的main目录下。这么一来客户端的aidl就无需编写了,直接和服务端的一模一样。包括路径的包名等。虽然你可以自己在客户端在写一遍aidl代码,为了不出错,请直接将服务端的aidl代码直接拷贝过来。
客户端调用代码如下
package com.example.xjp.myaidldemocustomer;import android.app.Activity;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.util.Log;import android.widget.ImageView;import android.widget.TextView;import com.example.xjp.aidla.IMyAidlInterface;public class MainActivity extends Activity { IMyAidlInterface mStub; TextView txt; private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e("xjp", "the Connected====>" + System.currentTimeMillis()); mStub = IMyAidlInterface.Stub.asInterface(service); if (mStub == null) { Log.e("xjp", "the mStub is null"); } else { try { int value = mStub.add(1, 8); txt.setText(value + ""); } 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); txt = (TextView) findViewById(R.id.text); Intent intent = new Intent(); //android 5.0以后直设置action不能启动相应的服务,需要设置packageName或者Component。 intent.setAction("com.xjp.myService"); intent.setComponent(new ComponentName("com.example.xjp.aidl", "com.example.xjp.aidl.MyServer")); //绑定服务 bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); Log.e("xjp", "the bindServer start..====>" + System.currentTimeMillis()); } @Override protected void onDestroy() { //解绑服务 unbindService(serviceConnection); super.onDestroy(); }}
如此一来,客户端也写好了。先安装服务端,在安装客户端。进入客户端之后实现了远程调用Service。
AIDL跨进程传递Bitamp对象
以上是最简单的 aidl跨进程传递java基本类型数据,最近在项目中遇到这么个需求,跨进程传递bitmap图片。当时看到这个需求就懵逼了,后来仔细分析其实是可以实现Android 利用Aidl实现跨进程传递 Bitmap对象。那么该怎么实现呢?
我们都知道Aidl支持跨进程传递 Java基本数据类型中包括byte这个类型,那么思路是不是来了呢?我们可以在服务端将需要传递的图片由bitmap转换成 byte[]类型。代码如下:
public byte[] getBitmap() { Bitmap bitmap = BitmapFactory.decodeResource(MyServer.this.getResources(), R.drawable.bg_top); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 90, baos);//压缩位图 return baos.toByteArray();//创建分配字节数组 }
如此一来就将Bitmap对象转换成byte[]类型了,现在aidl就可以跨进程传递byte[]类型数据。
在客户端你只需要将远程调用得到的byte[]类型转换成Bitmap对象,然后显示即可。客户端代码如下:
byte[] bytes = mStub.getBitmap();Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);img.setImageBitmap(bitmap);
是不是很简单,其实Aidl传递图片只是将Bitamp对象转换成byte[]类型,然后由byte[]类型在转换回Bitmap对象的一个过程。
- 注意:在亲测的过程中发现,利用aidl传递Bitamp对象是有一定的限制的,当Bitmap达到一定大小时是Aidl跨进程传递会失败。所以,利用Aidl跨进程可以传递较小的图片,至于多大可以根据你需求测试以免出错。这也是由于Aidl跨进程传递数据是有限的,数据过大就不适合利用aidl夸进程传递了,应该用Socket传递。因为Aidl跨进程间通信是一个实时的,同步的的一个过程,即Aidl的远程调用方法不能被阻塞,因此不能传递大数据。
总结
这是一个在AS下最简单的一个AIDL编程:
1.服务端创建一个aidl目录,然后在该目录下新建一个.aidl为后缀的接口类,该类定义远程调用的接口方法。
2.build编译之后会在app/build/generated/source/aidl/debug目录下会生成aidl远程实现类,该类是AS自动生成的。
3.在AndroidManifest.xml下配置Service的action和process属性。
4.将服务端的aidl目录拷贝到客户端相应的目录下,然后编写客户端调用代码,AS下简单的aidl编程就ok了。
5.利用Aidl实现跨进程传递较小的Bitmap对象。
更多相关文章
- Android高手进阶教程(十六)---Android中Intent传递对象的两种方
- android开发的3种方式
- Android作为服务端,PC推送消息
- Android上在两个Activity之间传递Bitmap对象
- eoe android客户端源码剖析(一)动画启动界面
- android socket
- android进程间通讯(3)--使用socket
- Android高手进阶教程(十七)之---Android中Intent传递对象的两种
- Android高手进阶教程(十七)之---Android中Intent传递对象的两种