前言

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中WebView的使用指南:
  2. Android学习开发路线图
  3. 利用Android(安卓)Studio、MAT对Android进行内存泄漏检测
  4. 【Android】实现登录、注册、数据库操作(极复杂)
  5. Android(安卓)Rtmp客户端搭建
  6. Gradle 依赖库下载
  7. Android(安卓)怎么样使用shape
  8. Android画图之抗锯齿(转)
  9. 创建和使用library

随机推荐

  1. android 将资源文件复制到android系统中
  2. Appium的DesiredCapabilities参数设置
  3. Android官方网站关于的tab layout的一个
  4. ArcGIS for Android 中MapView截图实现方
  5. android onTouchEvent 中只有ACTION_DOWN
  6. 软键盘android:windowSoftInputMode属性
  7. android Activity LifeCycle
  8. android打开文件方法
  9. 【Android(安卓)UI设计与开发】第03期:引
  10. Android 自定义标题栏