android AIDL详解

序言

aidl,android接口定义语言,用于进程间通信,是Binder实现的最好体现!关于Binder,大家可以看下这篇文章 Android Binder设计与实现
文章比较晦涩,但对于做应用层开发,了解下binder实现,还是很有必要的。

使用场景

都说aidl是用于进程间通信,但进程间通信其实我们平时用得比较少。很多平台级的产品却用了,比如百度地图,jpush,微信等。之前听一朋友说,他用了某推送平台,只要是其他app都用了这个推送,就能互相保活,我估计里面原理也是基于此。

具体使用

我现在模拟从一个app,去获取另外一个app中sharedpreference中数据。
首先,创建工程AIDL1,定义一个AidlTest.aidl文件:

package com.lxh.aidl;

interface AidlTest{
    String getData();
}

可以从gen目录下看到自动生成了java文件AidlTest.java。
然后定义一个service来与AidlTest中的Stub进行通信:

package com.lxh.aidl;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

/**
 * Created by luoxiaohui on 16/8/8.
 */
public class AidlService extends Service {

    private String TAG = "AidlService";

    @Override
    public IBinder onBind(Intent intent) {
        return mStub;
    }

    private AidlTest.Stub mStub = new AidlTest.Stub() {

        @Override
        public String getData() throws RemoteException {
            SharedPreferences sp = getSharedPreferences("aidl", Context.MODE_PRIVATE);
            String name = sp.getString("name","null");
            String age = sp.getString("age","null");
            String interest = sp.getString("interest","null");

            StringBuffer buffer = new StringBuffer();
            buffer.append("在aidl1中获取的姓名:"+name+";在aidl1中获取的年龄:"+age+";在aidl1中获取的兴趣爱好:"+interest);
            return buffer.toString();
        }
    };
}

最后,在activity中通过bindService()方法,实现与项目AIDL2进行远程通信:

//初始化sharedpreference数据,供AIDL2工程远程调用
    private void initData() {
        SharedPreferences sp = this.getSharedPreferences("aidl", Context.MODE_PRIVATE);
        SharedPreferences.Editor et = sp.edit();
        et.putString("name", "dafei");
        et.putString("age", "28");
        et.putString("interest", "billiards");
        et.commit();
    }

private void getDataFromAIDL2(){

        latch = new CountDownLatch(1);

        PackageManager pm = getPackageManager();
        final List resolveInfos = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);

        new Thread(new Runnable() {
            @Override
            public void run() {

                try{
                    for(PackageInfo packageInfo : resolveInfos){
                        String packageName = packageInfo.packageName;
                        if(packageName.equals("com.lxh.aidl2")){

                            Intent intent = new Intent("com.lxh.aidl");
                            ComponentName componentName = new ComponentName(packageName, AidlService.class.getName());
                            intent.setComponent(componentName);
                            MainActivity.this.bindService(intent,connection, Service.BIND_AUTO_CREATE);
                            //等待远程service结束,然后解除service
                            latch.await();
                            MainActivity.this.unbindService(connection);
                        }
                    }
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

            Log.d(TAG,"bind success...");
            try{
                aidlTest = AidlTest.Stub.asInterface(iBinder);
                String data = aidlTest.getData();
                dataView.setText(data);
                latch.countDown();
            }catch(Exception e){
                latch.countDown();
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e("MainActivity","onserviceDisconnected...");
            aidlTest = null;
        }
    };

    protected void onStop() {
        super.onStop();
        latch.countDown();
    };

目录结构如图所示:
android AIDL详解_第1张图片
项目中用到了CountDownLatch,关于此类介绍,可以在java CountDownLatch中一文看看。
到最后,别忘了在manifest中注册service,并给service加上属性

android:process=":remote"

加了冒号的表示是在应用内进程间共享,这里选择”remote”这个名字是随意主观的,你能用其他名字来让这个服务在另外的进程中运行。冒号’:’这个前缀将把这个名字附加到你的包所运行的标准进程名字的后面作为新的进程名称。

工程AIDL2跟AIDL1类似,只是在sharedpreference中设置的参数不一样~
最后打印的log如下所示:
android AIDL详解_第2张图片
到这儿,我们已经成功获取到另外一个app中的数据啦!

aidl文件生成的java文件

我们来看看AidlTest.aidl生成的java文件吧~

public interface AidlTest extends android.os.IInterface

从类的定义可以看出AidlTest是一个接口,继承了IInterface,然后里面有一个抽象内部类,继承了Binder,并实现了AidlTest这个自身类.

public static abstract class Stub extends android.os.Binder implements com.lxh.aidl.AidlTest
    {
        private static final java.lang.String DESCRIPTOR = "com.lxh.aidl.AidlTest";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an com.lxh.aidl.AidlTest interface,
         * generating a proxy if needed.
         */
        public static com.lxh.aidl.AidlTest asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.lxh.aidl.AidlTest))) {
                return ((com.lxh.aidl.AidlTest)iin);
            }
            return new com.lxh.aidl.AidlTest.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_getData:
            {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _result = this.getData();
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }
        private static class Proxy implements com.lxh.aidl.AidlTest
        {
            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 java.lang.String getData() throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getData, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        static final int TRANSACTION_getData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

我们重点看下这个方法:

public static com.lxh.aidl.AidlTest asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.lxh.aidl.AidlTest))) {
                return ((com.lxh.aidl.AidlTest)iin);
            }
            return new com.lxh.aidl.AidlTest.Stub.Proxy(obj);
        }

如果是同一个进程,返回((com.lxh.aidl.AidlTest)iin),如果不同进程,则返回代理new com.lxh.aidl.AidlTest.Stub.Proxy(obj)。

Demo下载地址
参考博客:
http://weishu.me/2016/01/12/binder-index-for-newer/

http://blog.csdn.net/singwhatiwanna/article/details/44590179

你可能感兴趣的:(android)