参考:
http://m.blog.youkuaiyun.com/article/details?id=51095169
http://blog.youkuaiyun.com/zjh1002492540/article/details/50750026
http://lib.youkuaiyun.com/article/android/31342
https://blog.youkuaiyun.com/ls5718/article/details/51854106 //binder机制的实现
https://blog.youkuaiyun.com/u010291868/article/details/73359890 //aidl和binder的区别
https://blog.youkuaiyun.com/qq_30379689/article/details/52253413 //博客文章也很不错
https://blog.youkuaiyun.com/jinxinliu1/article/details/70174591
https://blog.youkuaiyun.com/lb850747906/article/details/63683160
https://blog.youkuaiyun.com/codefly/article/details/17058607 //红茶一杯话Binder
https://segmentfault.com/a/1190000002982306 //java层binder进程间通信
Binder/AIDL学习起来还是蛮抽象的,还是要通过例子来加深理解,本文参照了几篇文章,在自己的平台上实现了一个简单的demo:两个数相加。
1、什么是Binder,什么是AIDL?
网上和书本上的介绍都很多,主要是为了实现进程间通信,可以参照下面的文章,
http://www.open-open.com/lib/view/open1464181227898.html
https://blog.youkuaiyun.com/codefly/article/details/17058607
2、Tool:Android Studio2.2.1 + Android5.1的手机
3、总结实现步骤:
1):建server端工程AidlServer,新建aidl文件,在接口里声明一个基本类型的API(实现两个数的加法)
2):建立MyService,实现接口的抽象类Stub(在Stub里定义/实现基本类型API)
3):将接口暴露给client,建立client端工程或module:逻辑实现启动连接远程服务,调服务里的基本类型API
4、具体过程:
AidlServer端
A:建立project:AidlExample,在这个project下面分别NeW->Module,建立两个module:AidlServer和AidlClient。
B:aidlserver端,新建aidl文件,在接口里声明一个基本类型的API,Build->make project会生成相应的java 文件。
B1:右键java文件夹,New->AIDL->AIDL File,输入interface name,Finish,生成aidl文件夹和相应的aidl文件。
B2:定义想要的API,比如实现两个数的加法,基本类型的API:int add(in int x,in int y),并将已有的basicTypes mark掉。
IMyAidlInterface.aidl文件的内容:
// IMyAidlInterface.aidl
package example.com.aidlserver;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
//void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
//double aDouble, String aString);
int add(in int x, in int y);
}
B3:Build->make project,会再在build->generated->source->aidl->debug下面生成对应aidl的java文件。
IMyAidlInterface.java文件的内容:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file:\AndroidStudioProjects\\AidlExample\\aidlserver\\src\\main\\aidl\\example\\com\\aidlserver\\IMyAidlInterface.aidl
*/
package example.com.aidlserver;
// Declare any non-default types here with import statements
public interface IMyAidlInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements example.com.aidlserver.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "example.com.aidlserver.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an example.com.aidlserver.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static example.com.aidlserver.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof example.com.aidlserver.IMyAidlInterface))) {
return ((example.com.aidlserver.IMyAidlInterface)iin);
}
return new example.com.aidlserver.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 example.com.aidlserver.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 x, int y) 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(x);
_data.writeInt(y);
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 x, int y) throws android.os.RemoteException;
}
C:aidlserver端建立MyService,实现aidl文件里Stub接口和基本类型API。
MainActivity端右键New->Service->Service,输入Class name,Finish.
MyService.java文件内容:
package example.com.aidlserver;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
return mBinder;
}
private IBinder mBinder = new IMyAidlInterface.Stub() {
@Override
public int add(int x, int y) throws RemoteException {
return x + y;
}
};}
}
D:AndroidManifest.xml文件里要配置action,用包名+service。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="example.com.aidlserver">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="example.com.aidlserver.MyService"/>
</intent-filter>
</service>
</application>
</manifest>
AidlClient端
E:将aidlserver->src->main下面的aidl文件夹copy到aidlclient->src->mian下面,保证server和Client的package名和aidl文件一致。
F:修改aidlclient的布局文件:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="example.com.aidlclient.MainActivity">
<EditText
android:id="@+id/num1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入数字" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+" />
<EditText
android:id="@+id/num2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入数字" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="=" />
<TextView
android:id="@+id/result"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/measure"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="AIDL 远 程计 算" />
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
G:修改aidlclient的逻辑文件MainActivity.java
在使用隐式开启服务的时候在5.0及以上版本默认是不能直接通过action开启的,使用意图的时候加上setpackage就可以解决.
package example.com.aidlclient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import example.com.aidlserver.IMyAidlInterface;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText num1,num2;
private TextView result,text;
private Button measure;
private IMyAidlInterface iMyAidl;
//连接远程服务
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iMyAidl = IMyAidlInterface.Stub.asInterface(service);
Log.i("TAG", "bind service successful");
}
@Override
public void onServiceDisconnected(ComponentName name) {
iMyAidl = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
num1 = (EditText) findViewById(R.id.num1);
num2 = (EditText) findViewById(R.id.num2);
measure = (Button) findViewById(R.id.measure);
result = (TextView) findViewById(R.id.result);
text = (TextView) findViewById(R.id.text);
measure.setOnClickListener(this);
bindService();
}
@Override
public void onClick(View v) {
try {
int i = iMyAidl.add(Integer.parseInt(num1.getText().toString()),Integer.parseInt(num2.getText().toString()));
result.setText("" + i);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void bindService() {
//使用意图对象绑定开启服务
Intent intent = new Intent();
intent.setAction("example.com.aidlserver.MyService");
//在5.0及以上版本必须要加上这个
intent.setPackage("example.com.aidlserver");
bindService(intent,conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
H:在手机上运行看看,AidlServer.apk和AidlClient.apk都要安装到手机上。这个时候点开aidlclient端的APK界面:
输入两个数,运行结果如下:
I:至此client调service的demo完成,例子在手机上验证成功。