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.aidl
package 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对象。

时间: 2024-08-03 11:49:47

Android studio 下的aidl编程实现Android的夸进程间通信的相关文章

Android studio 中创建AIDL Service

  1.概述  AIDL在android系统中的作用 AIDL,Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口.最近看了下AIDL在Android系统中的用法,在网上看到很多初学的朋友不太明白AIDL的实际作用,android提供了很多进程间通信的组件,像action.broadcast.contentprovide都可以实现进程间的通信,为什么还要用AIDL这个东西呢?我在a

Android Studio下HierarchyViewer的使用

什么是HierarchyViewer Hierarchy Viewer是随AndroidSDK发布的工具,位置在tools文件夹下,名为hierarchyviewer.bat.它是Android自带的非常有用而且使用简单的工具,可以帮助我们更好地检视和设计用户界面(UI),绝对是UI检视的利器,下面来详细介绍如何在Android Studio开发环境下使用Hierarchy Viewer. 如何在Android Studio开发环境下使用HierarchyViewer 1.启动模拟器,通过模拟器

在Android Studio下打jar包

这些天在研究Android 网络编程方面的东西,无奈在github上下载的Volley工程是Android Studio的目录结构,我向将其打成jar包,不管是在Studio下,还是在Eclipse下使用起来都会比较容易些.   研究了下Volley框架的目录结构 ,发现就是java代码目录和清单文件,对于这种库文件,还是很简单的.我们可以将其代码 拷到 我们的工程目录即可使用,相比之下我还是比较喜欢jar包.   其实在Android下有一种新型的 打包方式,那就是 aar ,在Android

Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用

在上一篇文章Android IPC机制(二)用Messenger进行进程间通信中我们介绍了使用Messenger来进行进程间通信的方法,但是我们能发现Messenger是以串行的方式来处理客户端发来的信息,如果有大量的消息发到服务端,服务端仍然一个一个的处理再响应客户端显然是不合适的.另外,Messenger用来进程间进行数据传递但是却不能满足跨进程的方法调用,接下来我们来使用AIDL来实现跨进程方法调用,此前我们都是用Eclipse来实现的,这次我们看看在Android Studio中使用AI

Android Studio实现Service AIDL

Android Studio实现Service AIDL [日期:2015-01-02] 来源:Linux社区  作者:teenyboy [字体:大 中 小] 今天要开发过程中要用到AIDL的调用,之前用的eclipse有大量教程,用起来很方便,现在刚换了Android studio,不可否认studio真的很强大,只是很多功能还需要摸索. AIDL(Android Interface Definition Language)是Android接口定义语言的意思,它可以用于让某个Service与多

Android studio 下的robotium自动化测试和持续集成

一.前言 Android Studio是一个Android开发环境,基于IntelliJ IDEA.类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试.作为官方主推的开发环境和停止对其他开发IDE的支持,Android Studio将成为今后唯一的android开发环境.本文主要介绍在Android Studio环境下的Robotium测试框架使用方法和持续集成. 二.在Android Studio中使用Robotium 2.1基础环

Android Studio下项目构建的Gradle配置及打包应用变体

Gradle简介 ??Gradle是一个自动化构建工具,采用Groovy的Domain Specific Language(领域特定语言)来描述和控制构建逻辑.具有语法简洁.可读性强.配置灵活等特点.基于Intellij IDEA社区版本开发的Android Studio天生支持Gradle构建程序.Groovy是一种基于JVM的敏捷开发语言,结合了Phthon.Ruby和Smalltalk的许多强大特性.同时,Groovy代码既能够与java代码很好地结合,也能够用于扩展现有的代码. Grad

Android Studio下SVN的用法(1) - 初识SVN

Android Studio下SVN的用法(1) - 初识SVN 前言 这几天公司又来了新人,之前都是一个人开发的项目现在需要合作开发.所以不可避免的需要使用版本控制工具. 公司使用的是SVN,网上有一大堆教程,但是发现对于新手来说,特别是从来没有接触过的人来说,往往都 说的不是很详细,甚至可以说基本没有照顾到这些方面.不要问我为什么这么清楚,因为被坑的不行了--.. PS:本篇文章是介绍AS下SVN的使用,所以可能会跟网上的教程不同 使用 下载及安装 首先前往官网下载SVN客户端,官网上下载可

android studio下的代码调试技巧的运用

记得当初刚开始学习java的时候,每次在eclipse上遇到调试程序的时候都是敲syso+快捷键,用system.out.printLn.输出语句来调试java的程序,哈哈哈,当初感觉确实蛮方便的,后来慢慢步入到安卓,然后使用安卓版的eclipse,在安卓代码当然是要杜绝java的输出语句了,于是又用输出日志Log的几种方式来调试,偶尔还会用到吐司调试(尴尬),eclipse版本的debug模式当初没怎么用习惯,只会简单的单步调试,于是就荒废了,虽然调试起来有点麻烦,但是用顺手了也还马马虎虎,但