Android使用Aidl实现跨进程通信

  前面一篇博客已经介绍了跨进程通信的几种方式,这篇博文主要实现一下Aidl方式的跨进程通信。 

  首先新建一个file文件,后缀名改为aidl,aidl文件内容与java文件差不多,我们写2个简单的方法意思一下

  Android使用Aidl实现跨进程通信_第1张图片

选择工程目录新建,直接就可以生成aidl文件

package com.caidong.aidl;
/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();

    /** 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);
}

定义的是接口而不是class这个需要注意一下,写好了之后如果使用的是android studio的话就需要清空工程然后重写编译工程了,就会自动生成IRemoteService.java文件


下面是自动生成的java文件的具体内容

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: C:\\Users\\caidongdong\\Desktop\\AidlTest\\app\\src\\main\\aidl\\com\\caidong\\aidl\\IRemoteService.aidl
 */
package com.caidong.aidl;
/** Example service interface */
public interface IRemoteService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.caidong.aidl.IRemoteService
{
private static final java.lang.String DESCRIPTOR = "com.caidong.aidl.IRemoteService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.caidong.aidl.IRemoteService interface,
 * generating a proxy if needed.
 */
public static com.caidong.aidl.IRemoteService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.caidong.aidl.IRemoteService))) {
return ((com.caidong.aidl.IRemoteService)iin);
}
return new com.caidong.aidl.IRemoteService.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_getPid:
{
data.enforceInterface(DESCRIPTOR);
int _result = this.getPid();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_basicTypes:
{
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();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.caidong.aidl.IRemoteService
{
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;
}
/** Request the process ID of this service, to do evil things with it. */
@Override public int getPid() 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);
mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/** Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/** Request the process ID of this service, to do evil things with it. */
public int getPid() throws android.os.RemoteException;
/** Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}
!注意这个文件最好不要去修改
然后写个服务使用这个aidl文件,新建一个service类

Android使用Aidl实现跨进程通信_第2张图片

下面是类的实现

public class DDService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("TAG","DDService onCreate........" + "Thread: " + Thread.currentThread().getName());
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("TAG","DDService onBind");
        return mBinder;
    }
    private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){

        @Override
        public int getPid() throws RemoteException {
            Log.i("TAG","Thread: " + Thread.currentThread().getName());
            Log.i("TAG","DDService getPid ");
            return Process.myPid();
        }

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
            Log.i("TAG","Thread: " + Thread.currentThread().getName());
            Log.i("TAG","basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString);
        }
    };

这个类主要就是在服务创建,绑定以及调用aidl跨进程通信的方法时打印日志

需要注意的一点在Manifest.xml文件中需要为这个service做一些配置,需要配置action,这就是其他进程访问时intent需要设置的action名称

        
            
                

                
            
        


到这里这个demo的第一个app就完成了,虽然很简陋功能很简单,下面再新建一个工程,通过aidl方式跨进程通信

将上一个工程的aidl文件拷贝到新建的工程中

Android使用Aidl实现跨进程通信_第3张图片

为什么要拷贝这个文件呢?

这个就是2个app直接够沟的桥梁,通过aidl文件传递数据

拷贝过来之后,同样的需要重新编译一下工程自动生成aidl文件同名的java文件,这样才能在项目中调用

下面看一下新建的工程的主要调用的代码

为了偷懒我就全写在了activity里边了,先贴上整个的代码,在解释一下各自的用途

public class MainActivity extends Activity {
    private IRemoteService remoteService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindService();
    }

    private void bindService() {
        Log.i("TAG","begin bindService");
        Intent intent = new Intent();
        intent.setAction("caidong.test.aidl");
        final Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent));
        bindService(eintent, connection, Context.BIND_AUTO_CREATE);
    }
    ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            remoteService =	IRemoteService.Stub.asInterface(service);
            try {
                int pid = remoteService.getPid();
                int currentPid = Process.myPid();
                Log.i("TAG","currentPID: " + currentPid +"  remotePID: " + pid);
                remoteService.basicTypes(12, 1223, true, 12.2f, 12.3, "我们的爱,不会再回来");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            Log.i("TAG","bind success! " + remoteService.toString());
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }

    public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List resolveInfo = pm.queryIntentServices(implicitIntent, 0);

        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }

        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);

        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);

        // Set the component to be explicit
        explicitIntent.setComponent(component);

        return explicitIntent;
    }
}

  首先新建了一个ServiceConnection对象,这里简单的介绍一下。

  应用组件(客户端)可以调用bindService()绑定到一个serviceAndroid系统之后调用serviceonBind()方法,它返回一个用来与service交互的IBinder绑定是异步的.bindService()会立即返回,它不会返回IBinder给客户端.要接收IBinder,客户端必须创建一个ServiceConnection的实例并传给bindService()。ServiceConnection包含一个回调方法,系统调用这个方法来传递要返回的IBinder。(注:只有activities,services,contentproviders可以绑定到一个service—你不能从一个broadcastreceiver绑定到service)回调有2个,一个是onServiceConnected服务连接成功,一个是onServiceDisconnected服务连接断开,这里在连接成功后就进行了数据的传递操作。

  然后是activity销毁的时候别忘了取消绑定服务onDestory()。然后重点来了,通过Intent绑定服务的时候,如果你的手机系统是5.0及以上的话,直接使用隐式调用服务就会抛出异常

Android使用Aidl实现跨进程通信_第4张图片

解决方法就是将隐式调用转换成显示调用,所有就有了createExplicitFromImplicitIntent(Context context,Intent intent)这个方法。

最后看看运行的效果,首先启动第一个app也就是最前面写的一个,看看控制台的打印使用TAG过滤掉不想看的

Android使用Aidl实现跨进程通信_第5张图片

然后启动第二个app,看看第二个app的控制台打印

Android使用Aidl实现跨进程通信_第6张图片

看到有信息打印,说明绑定服务成功了,然后再去看看第一个app的控制台有什么变化

Android使用Aidl实现跨进程通信_第7张图片

也有了打印,而且还有第二个app传送过来的数据,到这里这个demo就基本简单的实现了aidl跨进程的通信,下面给出下载这2个app的地址

app1  app2

你可能感兴趣的:(经验总结,AIDL,android,studio,android,通信)