AIDL探究

作者: xwp | 来源:发表于2016-07-19 11:19 被阅读39次

    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

    相关文章

      网友评论

        本文标题:AIDL探究

        本文链接:https://www.haomeiwen.com/subject/vjumjttx.html