前言

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对象。

更多相关文章

  1. Android高手进阶教程(十六)---Android中Intent传递对象的两种方
  2. android开发的3种方式
  3. Android作为服务端,PC推送消息
  4. Android上在两个Activity之间传递Bitmap对象
  5. eoe android客户端源码剖析(一)动画启动界面
  6. android socket
  7. android进程间通讯(3)--使用socket
  8. Android高手进阶教程(十七)之---Android中Intent传递对象的两种
  9. Android高手进阶教程(十七)之---Android中Intent传递对象的两种

随机推荐

  1. Intent打开系统设置界面(action列表)
  2. Android(安卓)DropBoxManager服务分析
  3. android 按home键返回到桌面后,再按桌面应
  4. Gradle build-info.xml not found for mo
  5. Android(安卓)MTK 修改TP参数
  6. android Studio 引用fresco 出现的问题
  7. Android Edittext设置负数以及小数
  8. TextView添加ClickableSpan和LinkMovemen
  9. Android的唤醒锁和键盘锁
  10. Android(安卓)sqlit java层源码分析