搞清楚AIDL

AIDL是 Android Interface definition language的缩写,一看就明白,它是一种Android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。
client app可通过aidl调用直接唤醒server app,类似于intent启动另一个app的activity,相比而言,在5.0以后,broadcast已经无法唤醒另一个未启动过的app。

AIDL的使用

最终效果
client调用aidl接口向server打招呼,server回调client的callback实现回应招呼。

搞清楚AIDL_第1张图片
客户端向服务端打招呼

搞清楚AIDL_第2张图片
服务端回调,回应客户端打招呼

一般是这样用的,client远程调用server端提供的service接口执行任务,server端回调,异步通知client端任务执行的状态。
客户端:
搞清楚AIDL_第3张图片

MainActivity

public class MainActivity extends Activity {

    private Button bindBtn;
    private Button greetBtn;
    private Button unbindBtn;
    private int count = 0;

    private IGreetBinder iGreetBinder;
    private Handler handler = new Handler();


    private IGreetCallback mCallback = new IGreetCallback.Stub() {

        @Override
        public void greetBack(final Person someone) throws RemoteException {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this,"greet back"+someone,Toast.LENGTH_LONG).show();
                }
            });
        }
    };

    private ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("ServiceConnection", "onServiceConnected() called");
            iGreetBinder = IGreetBinder.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            //This is called when the connection with the service has been unexpectedly disconnected,
            //that is, its process crashed. Because it is running in our same process, we should never see this happen.
            Log.i("ServiceConnection", "onServiceDisconnected() called");
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bindBtn = (Button) findViewById(R.id.bindBtn);
        bindBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("android.intent.action.AIDLService");
                bindService(intent, conn, Context.BIND_AUTO_CREATE);

                bindBtn.setEnabled(false);
                greetBtn.setEnabled(true);
                unbindBtn.setEnabled(true);
            }
        });

        greetBtn = (Button) findViewById(R.id.greetBtn);
        greetBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    count++;
                    String retVal = iGreetBinder.greet(new Person(count,"person"+count),mCallback);
                    Toast.makeText(MainActivity.this, retVal, Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    Toast.makeText(MainActivity.this, "error", Toast.LENGTH_SHORT).show();
                }
            }
        });

        unbindBtn = (Button) findViewById(R.id.unbindBtn);
        unbindBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(conn);

                bindBtn.setEnabled(true);
                greetBtn.setEnabled(false);
                unbindBtn.setEnabled(false);
            }
        });
    }
}

build.gradle

    sourceSets {
        main {
            java.srcDirs = ['src/main/java', 'src/main/aidl']
        }
    }

服务端:

搞清楚AIDL_第4张图片

AIDLService

public class AIDLService extends Service {

    private static final String TAG = "AIDLService";
    IGreetBinder.Stub stub = new IGreetBinder.Stub() {
        @Override
        public String greet(final Person someone, final IGreetCallback iGreetCallback) throws RemoteException {
            Log.i(TAG, "greet() called");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(100);
                        iGreetCallback.greetBack(someone);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            return "hello, " + someone;
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind() called");
        return stub;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "onUnbind() called");
        return true;
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy() called");
    }
}

AndroidManifest.xml


    
        
        // 需定义action,提供给客户端调起;
        
    

build.gradle

    sourceSets {
        main {
            java.srcDirs = ['src/main/java', 'src/main/aidl']
        }
    }

AIDL部分
服务端和客户端共用aidl部分。
Person.java

public class Person implements Parcelable {
    public int age;
    public String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(age);
        dest.writeString(name);
    }

    public void readFromParcel(Parcel in){
        name = in.readString();
        age = in.readInt();
    }

    protected Person(Parcel in) {
        age = in.readInt();
        name = in.readString();
    }

    public static final Creator CREATOR = new Creator() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    @Override
    public String toString() {
        return age + ":" + name;
    }
}

传递Person需要实现Parcelable接口。Aidl支持基本数据类型(int、long、char 等)String 和 CharSequence,List:只支持ArrayList,里面的每个元素都必须被AIDL支持。,Map: 只支持HashMap, 里面的每个元素都必须被AIDL支持。Parcelable: 所有实现了Parcelable接口的对象。
Parcelable 接口
Parcelable 可以是 android 系统将 objectes 分解成可以被进程处理的原始种类必须提供一个名为CREATOR的static final属性 该属性需要实现android.os.Parcelable.Creator接口,writeToParcel 注意写入变量和读取变量的顺序应该一致,不然得不到正确的结果,readFromParcel 注意读取变量和写入变量的顺序应该一致,不然得不到正确的结果。
Person.aidl

package com.test.aidldemo;
parcelable Person;

IGreetBinder.aidl

package com.test.aidldemo;
import com.test.aidldemo.IGreetCallback;
import com.test.aidldemo.Person;
interface IGreetBinder {
       String greet(inout Person person,IGreetCallback cb);
}

添加服务端对客户端的回调。
IGreetCallback.aidl

package com.test.aidldemo;
import com.test.aidldemo.Person;

interface IGreetCallback {
    void greetBack(inout Person person);
}

使用Person类型参数时,需要提供方向指示符,其包括in、out、和inout。in表示由客户端设置,out表示由服务端设置,inout表示客户端和服务端都设置了该值。如不设置方向指示符,将报错,基本类型int、String等无需设置方向指示符。

源码

client端:https://github.com/woshizmxin/AidlClientDemo
server端:https://github.com/woshizmxin/AidlServerDemo

在该demo运行在5.0以上设备上,会报错
** IllegalArgumentException: Service Intent must be explicit**
解决办法参考: Service Intent must be explicit的解决方法

使用Messager

如果想做app进程间通信,aidl写起来还是比较麻烦的,meassager则相当于是一个简化版本。它基于Message,相信大家都很熟悉,不需要编写aidl文件。
AIDL和Messager区别:

  1. Messenger本质也是AIDL,只是进行了封装,开发的时候不用再写.aidl文件。
    结合我自身的使用,因为不用去写.aidl文件,相比起来,Messenger使用起来十分简单。但前面也说了,Messenger本质上也是AIDL,故在底层进程间通信这一块,两者的效率应该是一样的。
  2. 在service端,Messenger处理client端的请求是单线程的,而AIDL是多线程的。使用AIDL的时候,service端每收到一个client端的请求时,就会启动一个线程(非主线程)去执行相应的操作。而Messenger,service收到的请求是放在Handler的MessageQueue里面,Handler大家都用过,它需要绑定一个Thread,然后不断poll message执行相关操作,这个过程是同步执行的。
    当然是有办法解决的,在server端,Messenger的Handler可以只当作一个转发器,不处理请求,只转发请求到相应的处理线程(多是相应的HandlerThread),这样也可以达到异步的效果。
  3. client的方法,使用AIDL获取返回值是同步的,而Messenger是异步的。Messenger只提供了一个方法进行进程间通信,就是send(Message msg)方法,发送的是一个Message,没有返回值,要拿到返回值,需要把client的Messenger作为msg.replyTo参数传递过去,service端处理完之后,在调用客户端的Messenger的send(Message msg)方法把返回值传递回client,这个过程是异步的,而AIDL你可以自己指定方法,指定返回值,它获取返回值是同步的。

具体使用请移步:
Android 基于Message的进程间通信 Messenger完全解析

参考文章

Android中使用AIDL时的跨进程回调—Server回调Client
Service Intent must be explicit的解决方法
Android 基于Message的进程间通信 Messenger完全解析

你可能感兴趣的:(搞清楚AIDL)