AIDL探究

AIDL机制:

参考鸿阳博客:http://blog.csdn.net/lmj623565791/article/details/38461079.

Binder能干什么?

Binder可以提供系统中任何程序都可以访问的全局服务。这个功能当然是任何系统都应该提供的,下面我们简单看一下Android的Binder的框架.

Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;简单想一下,需要提供一个全局服务,那么全局服务那端即是服务器接口,任何程序即客户端接口,它们之间通过一个Binder驱动访问。

服务器端接口:实际上是Binder类的对象,该对象一旦创建,内部则会启动一个隐藏线程,会接收Binder驱动发送的消息,收到消息后,会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码。

Binder驱动:该对象也为Binder类的实例,客户端通过该对象访问远程服务。

客户端接口:获得Binder驱动,调用其transact()发送消息至服务器
如果大家对上述不了解,没关系,下面会通过例子来更好的说明,实践是检验真理的唯一标准嘛

AIDL文件自动生成

androidstudio自动生成 new --> aidlfile

interface IPushAidl {
/**
 * 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);

void startNotify();

void stopNotify();

}

其中 #basicTypes是自带有,上面注释是说:示范一些基本类型,在AIDL中你能用他们作为参数与返回值.具体作用不知.
自己定义了startNotify与stopNotify方法.

编译后生成一个IPushAidl.java文件

public interface IPushAidl extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements cn.lunkr.example.android.testmultiprocessreacte.aidl.IPushAidl
}

里边有一个内部类Stub继承Binder并且实现IPushAidl的方法

Service的代码:

public class PushService extends Service {
private NotificationManager mNm;
private final static int NOTIFY_ID = 1;
private MyBinder mBinder = new MyBinder();
private final static String TAG = PushService.class.getSimpleName();

@Nullable
@Override
public IBinder onBind(Intent intent) {
    Log.d(TAG, "onBind");
    return mBinder;
}

@Override
public void onCreate() {
    Log.d(TAG, "onCreate");
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "onStartCommand");
    return super.onStartCommand(intent, flags, startId);
}

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

public final void startNotification() {
    Log.d(TAG, "startNotification");
    Notification.Builder builder = new Notification.Builder(this);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
            new Intent(this, MainActivity.class), 0);
    builder.setContentIntent(contentIntent);
    builder.setSmallIcon(R.mipmap.ic_launcher);
    builder.setTicker("Foreground Service Start");
    builder.setContentTitle("Foreground Service");
    builder.setContentText("Make this service run in the foreground.");
    Notification notification;
    if (Build.VERSION.SDK_INT >= 16) {
        notification = builder.build();
    } else {
        notification = builder.getNotification();
    }
    mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mNm.notify(NOTIFY_ID, notification);//first parameter not < 0
}

public final void stopNotification() {
    Log.d(TAG, "stopNotification");
    mNm.cancel(NOTIFY_ID);
}

class MyBinder extends IPushAidl.Stub {
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

    }

    @Override
    public void startNotify() {
        startNotification();
    }

    @Override
    public void stopNotify() {
        stopNotification();
    }
}
}

绑定service用的activity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button startService, stopService, bindService, unbindService, startNotify, stopNotify;

private IPushAidl myBinder;

private ServiceConnection connection = new ServiceConnection() {

    @Override
    public void onServiceDisconnected(ComponentName name) {
        myBinder = null;
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        myBinder = IPushAidl.Stub.asInterface(service);
    }

};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    startService = (Button) findViewById(R.id.start_service);
    stopService = (Button) findViewById(R.id.stop_service);
    bindService = (Button) findViewById(R.id.bind_service);
    unbindService = (Button) findViewById(R.id.unbind_service);
    startNotify = (Button) findViewById(R.id.start_notify);
    stopNotify = (Button) findViewById(R.id.stop_notify);
    startService.setOnClickListener(this);
    stopService.setOnClickListener(this);
    bindService.setOnClickListener(this);
    unbindService.setOnClickListener(this);
    startNotify.setOnClickListener(this);
    stopNotify.setOnClickListener(this);

}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.start_service:
            Intent startIntent = new Intent(this, PushService.class);
            startService(startIntent);
            break;
        case R.id.stop_service:
            Intent stopIntent = new Intent(this, PushService.class);
            stopService(stopIntent);
            break;
        case R.id.bind_service:
            Intent bindIntent = new Intent(this, PushService.class);
            bindService(bindIntent, connection, BIND_AUTO_CREATE);
            break;
        case R.id.unbind_service:
            unbindService(connection);
            break;
        case R.id.start_notify:
            if (myBinder != null) {
                try {
                    myBinder.startNotify();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            break;
        case R.id.stop_notify:
            if (myBinder != null) {
                try {
                    myBinder.stopNotify();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            break;
        default:
            break;
    }
}
}

原理探究:

service 里边定义了内部类MyBinder继承IPushAidl.Stub,实现startNotify()与stopNotify().

系统会维护一个IPushAidl的代理类IPushAidlProxy(里边的方法与IPushAidl一致)

MainActivity在绑定Service的时候,将返回一个IBinder(猜测为代理类)

{
myBinder = IPushAidl.Stub.asInterface(service);
public static cn.lunkr.example.android.testmultiprocessreacte.aidl.IPushAidl asInterface(android.os.IBinder      obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof cn.lunkr.example.android.testmultiprocessreacte.aidl.IPushAidl))) {
return ((cn.lunkr.example.android.testmultiprocessreacte.aidl.IPushAidl)iin);
}
return new cn.lunkr.example.android.testmultiprocessreacte.aidl.IPushAidl.Stub.Proxy(obj);
}

然后MainActivity通过调用startNotify与stopNotify

(其实有代理类通过mRemote调用service的Stub中的onTransact()执行相应的方法

mRemote.transact(Stub.TRANSACTION_startNotify, _data, _reply, 0)

代理类中的参数传递的实现:

_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);

Stub参数的读取:

data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
//reply.writeInt(_result);调用result的返回
private android.os.IBinder mRemote;

到此,我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Binder驱动(mRemote),即服务端与客户端连接的桥梁。

不生成Aidl实现多进程Service方法调用

  1. PushService内部类gistcode

内部类:

class MyBinder extends Binder {
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case 1://startNotify
                data.enforceInterface(DESCRIPTOR);
                startNotification();
                reply.writeNoException();
                return true;
            case 2://stopNotify
                data.enforceInterface(DESCRIPTOR);
                stopNotification();
                reply.writeNoException();
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

}

private MyBinder mBinder = new MyBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
    Log.d(TAG, "onBind");
    return mBinder;
}
  1. MainActivity中gistcode:

     private ServiceConnection connection = new ServiceConnection() {
     @Override
     public void onServiceDisconnected(ComponentName name) {
         myBinder = null;
     }
    
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         myBinder = service;
     }
     };
    
     @Override
     public void onClick(View v) {
     switch (v.getId()) {
         case R.id.start_service:
             Intent startIntent = new Intent(this, PushService2.class);
             startService(startIntent);
             break;
         case R.id.stop_service:
             Intent stopIntent = new Intent(this, PushService2.class);
             stopService(stopIntent);
             break;
         case R.id.bind_service:
             Intent bindIntent = new Intent(this, PushService2.class);
             bindService(bindIntent, connection, BIND_AUTO_CREATE);
             break;
         case R.id.unbind_service:
             unbindService(connection);
             break;
         case R.id.start_notify:
             if (myBinder != null) {
                 bindMethod(1);
             }
             break;
         case R.id.stop_notify:
             if (myBinder != null) {
                 bindMethod(2);
             }
             break;
     }
     }
    
     public void bindMethod(int id) {
     if (myBinder == null) {
         return;
     }
     android.os.Parcel _data = android.os.Parcel.obtain();
     android.os.Parcel _reply = android.os.Parcel.obtain();
     try {
         _data.writeInterfaceToken("PushService2");
         myBinder.transact(id, _data, _reply, 0);
     } catch (RemoteException e) {
         e.printStackTrace();
     } finally {
         _data.recycle();
         _reply.recycle();
     }
     }
    

补充:

传递参数_data.writeXxx(xxx),_data.readXxx(xxx);

看了网上关于AIDL的一些博客,从原理来解释AIDL是什么,再回头看自己以前的理解,想法如下:

  1. 很基本的原理看完对整体设计是有提升.
  2. 以后自己的文章,要简如接口设计.

demo:

https://github.com/xwpeng/TestAidl.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,460评论 25 707
  • 上篇文章介绍了IPC机制的基本概念以及简单使用,文章链接:Android 关于IPC机制的理解(一) 这篇文章主要...
    老实任阅读 703评论 0 2
  • Android跨进程通信IPC整体内容如下 1、Android跨进程通信IPC之1——Linux基础2、Andro...
    隔壁老李头阅读 10,720评论 13 43
  • 1.参与态度决定最终收获 中间有一周时间很忙,每天打卡一直处于走形式的状态,明显感觉那段时间的进步较刚参加时进步小...
    寒门书生阅读 361评论 0 0
  • 亚当夏娃日记--亚当日记--星期五 我已经尽了自己的努力,可是所有事物仍然在被一一命名。我的这片领地本来名叫伊甸园...
    看剧吗阅读 482评论 0 0