本文参考文献:《疯狂Android讲义 : 第2版 》

本文中的示例参考自 《[android跨进程通信(IPC):使用AIDL](http://blog.csdn.net/singwhatiwanna/article/details/17041691)》

本文中的两个 app 的示例源代码的 main 目录文件下载地址 密码: 2kwk

Android 远端调用 Service 是先定义一个远端调用接口,然后为该接口提供一个实现类即可。

客户端访问 Service 时,Android 并不是直接返回 Service 对象给客户端 —— 与本地绑定 Service 时类似,Service 只是将 Service 的代理对象(IBinder对象)通过 onBind() 方法返回给客户端。因此 Android 的 AIDL 远程接口的实现类就是那个 IBinder 实现类。

与绑定本地 Service 不同的是,本地 Service 的 onBind() 方法会直接把 IBinder 对象本身传给客户端的 ServiceConnection 的 onServiceConnected 方法的第二个参数。但远程 Service 的 onBind() 方法只是将 IBinder 对象的代理传给客户端的 ServiceConnection 的 onServiceConnected 方法的第二个参数。

当客户端获取了远程 Service 的 IBinder 对象的代理之后,接下来就可通过该 IBinder 对象去回调远程 Service 的属性或方法了。

创建 AIDL 文件

AIDL 接口定义语言的语法十分简单,这种接口定义语言并不是一种真正的编程语言,它只是定义两个进程之间的通信接口:

  1. AIDL 定义接口的源代码必须以 .aidl 结尾;
  2. AIDL 接口中用到数据类型,除了基本类型、String、List、Map、CharSequence 之外,其他类型全部都需要导包,即使它们在同一个包中也需要导包。

AIDL 使用示例

Service 端代码

本示例中要使用的用于提供给客户和服务端使用的 Student.java 类文件的内容:

package com.example.toby.aidlservice;import java.util.Locale;import android.os.Parcel;import android.os.Parcelable;/** * Created by toby on 17-4-28. */public final class Student implements Parcelable {    public static final int SEX_MALE = 1;    public static final int SEX_FEMALE = 2;    public int sno;    public String name;    public int sex;    public int age;    public Student() {    }    public static final Parcelable.Creator CREATOR = new            Parcelable.Creator() {                public Student createFromParcel(Parcel in) {                    return new Student(in);                }                public Student[] newArray(int size) {                    return new Student[size];                }            };    private Student(Parcel in) {        readFromParcel(in);    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(sno);        dest.writeString(name);        dest.writeInt(sex);        dest.writeInt(age);    }    public void readFromParcel(Parcel in) {        sno = in.readInt();        name = in.readString();        sex = in.readInt();        age = in.readInt();    }    @Override    public String toString() {        return String.format(Locale.ENGLISH, "Student[ %d, %s, %d, %d ]", sno, name, sex, age);    }}

接下来需要在工程中右键创建 AIDL 文件,并创建如下两个 AIDL 接口文件:

  1. AIDL 接口文件 Student.aidl 代码:
// Student.aidl.aidlpackage com.example.toby.aidlservice;// Declare any non-default types here with import statementsparcelable Student;
  1. AIDL 接口文件 IMyService.aidl 代码:
// IMyService.aidlpackage com.example.toby.aidlservice;// Declare any non-default types here with import statementsimport com.example.toby.aidlservice.Student;interface IMyService {    List getStudent();    void addStudent(in Student student);}

服务端的 MyService.java 代码:

package com.example.toby.aidlservice;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.Parcel;import android.os.RemoteException;import android.util.Log;import java.util.ArrayList;import java.util.List;/** * Created by toby on 17-4-28. */public class MyService extends Service {    private final static String TAG = "MyService";    private static final String PACKAGE_CLIENT = "com.example.toby.aidlclient";    private boolean mCanRun = true;    private List mStudents = new ArrayList<>();    //这里实现了aidl中的抽象函数    private final IMyService.Stub mBinder = new IMyService.Stub() {        @Override        public List getStudent() throws RemoteException {            synchronized (mStudents) {                return mStudents;            }        }        @Override        public void addStudent(Student student) throws RemoteException {            synchronized (mStudents) {                if (!mStudents.contains(student)) {                    mStudents.add(student);                }            }        }        //在这里可以做权限认证,return false意味着客户端的调用就会失败,比如下面,只允许包名为com.example.test的客户端通过,        //其他apk将无法完成调用过程        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)                throws RemoteException {            String packageName = null;            String[] packages = MyService.this.getPackageManager().                    getPackagesForUid(getCallingUid());            if (packages != null && packages.length > 0) {                packageName = packages[0];            }            Log.d(TAG, "onTransact: " + packageName);            if (!PACKAGE_CLIENT.equals(packageName)) {                return false;            }            return super.onTransact(code, data, reply, flags);        }    };    @Override    public void onCreate() {        Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");        thr.start();        synchronized (mStudents) {            for (int i = 1; i < 6; i++) {                Student student = new Student();                student.name = "student#" + i;                student.age = i * 5;                mStudents.add(student);            }        }        super.onCreate();    }    @Override    public IBinder onBind(Intent intent) {        Log.d(TAG, String.format("on bind,intent = %s", intent.toString()));        return mBinder;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        mCanRun = false;        super.onDestroy();    }    class ServiceWorker implements Runnable {        long counter = 0;        @Override        public void run() {            // do background processing here.....            while (mCanRun) {                Log.d("scott", "" + counter);                counter++;                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}

服务端的 MainActivity.java 是自动生成的代码:

package com.example.toby.aidlservice;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }}

服务端的 activity_main.xml 是自动生成的代码:

<?xml version="1.0" encoding="utf-8"?>    

服务端的 AndroidManifest.xml 文件的内容:

<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                        

服务端的工程中的文件布局图:

Android Studio 配置使用 AIDL 跨应用通信示例_第1张图片 服务端的工程中的文件布局图

Client 端代码

正如前面提到的,AIDL 接口定义了两个进程之间的通信接口,因此不仅服务器端需要 AIDL 接口,客户端同样需要前面定义的 AIDL 接口,因此开发客户端的第一步就是将 Service 端的 AIDL 接口文件复制到客户端应用中。本例中我们同时还要复制 Student.java 文件到客户端。

拷贝完成之后的工程结构图如下:

Android Studio 配置使用 AIDL 跨应用通信示例_第2张图片 拷贝完成之后的工程结构图

** 注意,上图中的 Student.java 以及两个 AIDL 文件的包名目录结构。 **

客户端绑定远程 Service 与绑定本地 Service 的区别并不大,同样只需要两步:

  1. 创建 ServiceConnection 对象;
  2. 以 ServiceConnection 对象作为参数,调用 Context 的 bindService() 方法绑定远程 Service 即可。

与绑定本地 Service 不同的是,绑定远程 Service 的 ServiceConnection 并不能直接获取 Service 的 onBind() 方法所返回的对象,它只能返回 onBind() 方法所返回的对象的代理,因此在 ServiceConnection 的 onServiceConnected 方法中需要通过如下代码进行处理:

mIMyService = IMyService.Stub.asInterface(service);

客户端的 MainActivity.java 代码:

package com.example.toby.aidlclient;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AlertDialog;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import com.example.toby.aidlservice.IMyService;import com.example.toby.aidlservice.Student;public class MainActivity extends AppCompatActivity {    private static final String ACTION_BIND_SERVICE = "com.example.toby.aidlservice.MyService";    private IMyService mIMyService;    private ServiceConnection mServiceConnection = new ServiceConnection()    {        @Override        public void onServiceDisconnected(ComponentName name)        {            mIMyService = null;        }        @Override        public void onServiceConnected(ComponentName name, IBinder service)        {            //通过服务端onBind方法返回的binder对象得到IMyService的实例,得到实例就可以调用它的方法了            mIMyService = IMyService.Stub.asInterface(service);        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Intent intentService = new Intent(ACTION_BIND_SERVICE);        intentService.setPackage("com.example.toby.aidlservice");        intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        MainActivity.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);    }    public void showDialog(String message)    {        new AlertDialog.Builder(MainActivity.this)                .setTitle("scott")                .setMessage(message)                .setPositiveButton("确定", null)                .show();        Log.d("","Toby===============================");    }    @Override    protected void onDestroy() {        if (mIMyService != null) {            unbindService(mServiceConnection);        }        super.onDestroy();    }    public void btnClick(View view) {        try {            if(mIMyService != null) {                Student student = mIMyService.getStudent().get(0);                showDialog(student.toString());            }        } catch (RemoteException e) {            e.printStackTrace();        }    }}

客户端的主布局文件的代码:

<?xml version="1.0" encoding="utf-8"?>    

程序的运行效果如下:

Android Studio 配置使用 AIDL 跨应用通信示例_第3张图片 显示效果

更多相关文章

  1. Android 资源文件夹下的文件不能有大写字符,会导致R.java无法生成
  2. Android接口安全 - RSA+AES混合加密方案
  3. android的文件系统结构简单介绍
  4. Android NFS 文件系统
  5. Android接口定义语言---AIDL(一)
  6. Android中VideoView播放当前工程中视频文件的方法

随机推荐

  1. android:paddingLeft和android:layout_ma
  2. 最近总结的android疑惑
  3. android 开发环境的搭建
  4. Android(安卓)AOSP基础(五)不会调试系统源
  5. android 相对布局属性
  6. Android的UI书写的四种方法
  7. Controls over the EditText and the IME
  8. android系统定制从听说到入门三
  9. Android(安卓)xml资源文件中@、@android:
  10. Android(安卓)中文API合集(4)(102篇)(chm