首先讲下AIDL的使用其实就是服务的跨进程通信了,那么我们就写一个活动和服务的跨进程通信吧。

第一步:我们就在AS里面新建一个AIDL文件(PS:现在AS建AIDL不要求和的java的包名相同了)

aidl文件(PS:使用android studio创建,make项目)

接着你同步项目一下就可以在app / generated / source / aidl / debug / aidl里面发现由aidl文件生成的java文件



interface IMyAidlInterface {
   String getName(String name);
}



可以看到,在这里面我们就一个方法getName(String name),接受一个字符串参数,然后返回一个字符串,相当的简单。

package com.update.myaidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by kim on 2018/4/9.
 */

public class MyService  extends Service{
    public final static String TAG="MyService";

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

    private IBinder binder=new IMyAidlInterface.Stub() {
        @Override
        public String getName(String name) throws RemoteException {
            Log.i(TAG,name);
            return "我是kim";
        }

    };

    @Override
    public void onCreate() {
        super.onCreate();
    }


}


这里我们写了一个服务,看一下也比较简单。先新了一

IMyAidlInterface


.Stub()并把它向上转型成了的的IBinder,最后在onBind方法中返回回去。可能你注意到了,在

IMyAidlInterface


.Stub()的内部我们重写getName(String name)方法,没错这就是我们aidl文件中定义的接口。


对了,因为我们希望看到的是跨进程通信,所以我们把为MyService定义成新启动一个进程:

定义为启动在新进程中,只需要在AndroidMainfest.xml中声明是加上一个过程属性即可,不过这里有两个地方值得注意:
1.组件默认的进程名就是包名; 
2.定义新的进程名的时候需要以包的形式(例如:

com.update.myaidl

)。

接着,我们继续向下看:

package com.update.myaidl;

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;

public class MainActivity extends AppCompatActivity {

    public final static String TAG="MainActivity";
    private IMyAidlInterface myAidlInterface;



    private ServiceConnection serviceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            Log.i(TAG,"连接service 成功");
            try {
                String s=myAidlInterface.getName("我是kim,快开门");
                Log.i(TAG,"从Service得到的字符串:"+s);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG,"连接失败");


        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //开启并绑定服务
        Log.i(TAG,"onCreate");
        startAndBindService();
    }

    private void startAndBindService() {
        Intent service = new Intent(MainActivity.this, MyService.class);
        //startService(service);
        bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);

    }
}


由于主要是服务和活动间的通信,所以为了让代码整洁就没有写UI了。

在onCreate(Bundle savedInstanceState)中,我们调用了自己定义的一个方法startAndBindService(),这个方法里面我们生成了一个Intent,然后bindService了这个Intent传入了三个参数分别是Intent,ServiceConnection,Flag。

意向我们就不用说了,我们看后面两个参数:
。在活动中,我们新了一个ServiceConnection并实现了他的两个方法onServiceConnected,onServiceDisconnected在onServiceConnected中我们通过IMyAidlInterface.Stub.asInterface(服务)把传来的的的IBinder转换成了我们定义的IMyInterface的的。然后我们调用了的getName方法,传递了个字符串和获取从为为MyService传来的字符串,并且打印了日志。

对于我们传的Context.BIND_AUTO_CREATE的意思就是说:如果绑定服务的时候,服务还没有被创建,就创建它当然,这里还有很多标志,我也不一一说了。

然后,我们的编码就完成了,开始运行测试一下把!

android aidl 常量 android aidl使用步骤_数据


看一下运行结果,在这两个不同的进程中都得到了我们想要的结果,所以,一个用AIDL实现的跨进程通信就这样完成了。当然我们的演示(这次不能拼错了)中,的getName没有任何逻辑,你也可以加一些逻辑去执行一些复杂的操作。


AIDL的理解:

现在我们会使用AIDL了,那我们还不去掀开它神秘的面纱。

服务中的IBinder 
还记得我们在MyService中利用新IMyInterface.Stub()向上转型成了IBinder然后在onBind方法中返回的。那我们就看看IMyInterface.Stub吧:

public static abstract class Stub extends android.os.Binder implements aidl.IMyInterface {
..........
}

可以看到,存根是IMyInterface的的中的一个静态抽象类,继承了活页夹,并且实现了IMyInterface的的接口。这也就解释了我们定义IMyInterface.Stub的时候为什么需要实现IMyInterface的的中的方法了,也说明了为什么我们可以把IMyInterface.Stub向上转型成的的IBinder了。

活动中的IMyInterface的的
在活动中,通过ServiceConnection连接为为MyService并成功回调onServiceConnected中我们把传回来的的的IBinder通过IMyInterface.Stub.asInterface(服务)转换成为IMyInterface的的,那就来看看这里是如何转换的吧:

public static abstract class Stub extends android.os.Binder implements aidl.IMyInterface {

..........

public static aidl.IMyInterface asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    //检查Binder是不是在当前进程
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof aidl.IMyInterface))) {
        return ((aidl.IMyInterface) iin);
    }
    return new aidl.IMyInterface.Stub.Proxy(obj);
}
}

首先,我们因该明白的是,传回来的的IBinder就是我们在服务的onBind()方法所返回的的IBinder,然后我们调用作为接口并把结果返回的的IBinder当参数传
进去。在asInterface方法中,首先判断了传进来的的的IBinder是不是空,如果为空就返回一个空值;接着就判断传进来的的的IBinder是不是就在当前进程里面,如果是的话就直接返回IMyInterface的的,不是的话就返回IMyInterface的的.Stub.Proxy(OBJ)这里我觉得需要明白的是:。直接返回的IMyInterface的是实现了定义的接口方法getInfor的因为在IMyInterface.Stub中所实现的当然如果是在同一进程中,那么我们调用IMyInterface的的的方法时就是在本地调用方法,直接调用就可以了。

如果没在同一进程,就会返回IMyInterface.Stub.Proxy(OBJ):

private static class Proxy implements aidl.IMyInterface {
        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 getInfor(java.lang.String s) 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);
                _data.writeString(s);
               //传送数据到远程的
                mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
                _reply.readException();
              //接受从远端传回的数据
                _result = _reply.readString();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        } 
   }
    static final int TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}

在代理服务器中,我们首先把服务连接成功返回的的的IBinder它的内部变量mRemote,这里在提一下,这里得的的IBinder还是是为为MyService中onBind所返回的。然后,当我们调用IMyInterface的的的方法的时候,其实就是调用的代理服务器的方法了,这也是为什么这个类叫做Porxy的原因了。

当调用IMyInterface.getInfor(String s),我们就看代理中的getInfor,先获取两个parcel对象_data,_data,从变量名就可以看出,一个是传数据的,另一个则是接受返回数据的。接着,向_data中写入了DESCRIPTOR(也就是这个类的全名),再写入了方法参数。然后就到了最重要的一步了,

mRemote.transact(Stub.TRANSACTION_getInfor,_data,_reply,0); 
。这里我们调用了的IBinder的办理方法,来把数据传给远端的服务器然后在我们远程的为MyService中,里面的存根中就会回调onTransact ()(因为你把数据传个远程的服务,远端的服务收到数据也就回调了)

注意:这里是在远程的服务里调用的。

@Overridepublic 
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_getInfor: {
            data.enforceInterface(DESCRIPTOR);
            java.lang.String _arg0;
           //取出参数
            _arg0 = data.readString();
           // 远程服务调用自己本地实现的方法获取返回值
            java.lang.String _result = this.getInfor(_arg0);
            reply.writeNoException();
           //写入返回值
            reply.writeString(_result);
            return true;
        }
    }
    return super.onTransact(code, data, reply, flags);
}

onTransact方法是在末节的内部实现的。

先看一下它的四个参数: 
code:每个方法都有一个int类型的数字用来区分(后面中的swicth),在我们例子中也就是我们Proxy中的Stub.TRANSACTION_getInfor.data
:传过来  的数据,其中包含我们的参数,以及类的描述。
回复:传回的数据,我们要写入是否发生了异常,以及返回值
国旗:该方法是否有返回值,0表示有返回值。

调用onTransact就表示有数据传来,首先就会通过swicth判断是哪个方法,然后取出方法参数,调用本地实现的方法获取返回值,写入返回值到答复。最后,返回真,才会把数据发送出去,发挥虚假就不会把结果返回给活动了。这里也就是说,只有返回真实的,我们代理中才能接受从远端传回的数据。

//传送数据到远程的
        mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
        _reply.readException();
       //接受从远端传回的数据
        _result = _reply.readString();

注意:服务也是把数据发送出来,让客户端接受的。

服务发出了数据,客户端接收到了,就会一层一层返回去。所以,当我们简单的调用IMyInterface的的的getInfor时候,先是代理的办理发送出数据,然后服务端的onTransact接受并处理传来的数据,再把处理得到的数据写入返回值并发送给客户端,客户端读取值后就成为调用方法的返回值返回了。

然后AIDL的基本原理就是这样了,看明白了AIDL,才发现原来AIDL不过就是帮我们生成了那些数据写入,传送,读取的方法而已。所以,我们自己写一个不要AIDL的跨进程通信也是挺简单的,快动手试试吧!