Android AIDL的使用以及双向传输数据

        Android Interface Definition Language,简称AIDL,是Android接口定义语言,用于进程间通信。当然你也可以通过发送广播达到进程间通信的目的,但广播会碰到延迟等现象,个人建议还是使用AIDL。

        AIDL传输数据支持Java基本数据类型、List、Map以及实现Parcelable的类。接下来将通过一个实例来讲解下AIDL,并支持双向传输,使用Android Studio开发。

        AIDL有服务端和客户端,在服务端,我们先在aidl.com.android.demo路径下生成一个后缀为.aidl的DemoInfo.aidl文件,内容如下:

package com.android.demo;
parcelable DemoInfo;
   里面不做什么,只是定义了一个序列化对象。这是到时候AIDL要传递的数据,我们在java.com.android.demo路径下生成DemoInfo.java去实现。
package com.android.demo;

import android.os.Parcel;
import android.os.Parcelable;

public class DemoInfo implements Parcelable {
    private int mValue1 = -1;
    private int mValue2 = -1;

    public int getValue1() {
        return mValue1;
    }

    public void setValue1(int mValue1) {
        this.mValue1 = mValue1;
    }

    public int getValue2() {
        return mValue2;
    }

    public void setValue2(int mValue2) {
        this.mValue2 = mValue2;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public void readFromParcel(Parcel in) {
        mValue1 = in.readInt();
        mValue2 = in.readInt();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mValue1);
        dest.writeInt(mValue2);
    }

    public static final Creator<DemoInfo> CREATOR = new Creator<DemoInfo>() {
        @Override
        public DemoInfo createFromParcel(Parcel source) {
            DemoInfo mInfo = new DemoInfo();
            mInfo.mValue1 = source.readInt();
            mInfo.mValue2 = source.readInt();
            return mInfo;
        }

        @Override
        public DemoInfo[] newArray(int size) {
            return new DemoInfo[size];
        }
    };
}

        接下来,为了服务端也能向客户端传输数据,我们写个CallBack,供客户端去注册监听回调。在aidl.com.android.demo路径下生成一个后缀为.aidl的DemoCallBack.aidl文件。

package com.android.demo;
import com.android.demo.DemoInfo;

interface DemoCallback {
    void sendCtrlData(in DemoInfo info);
}

        因为是传递序列化参数,所以AIDL需要我们写明方向,总共有三种: in , out , inout 。in 表示数据由客户端流向服务端, out 表示数据由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。接下来我们再在aidl.com.android.demo路径下生成一个后缀为.aidl的DemoInterface.aidl文件,内容如下:

package com.android.demo;

import com.android.demo.DemoCallback;

interface DemoInterface {
    void getResult(boolean bool);
    void registListener(DemoCallback listener);
    void unregistListener(DemoCallback listener);
}

里面写了供客户端传递数据、注册监听回调和释放监听回调的接口。接下来服务端要提供 IBinder供客户端连接,实现如下:

package com.android.demo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;

public class AidlService extends Service {
    private static AidlService mService = null;
    private static RemoteCallbackList<DemoCallback> mListener=new RemoteCallbackList<>();
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mListener.kill();
    }

    private DemoInterface.Stub stub = new DemoInterface.Stub() {
        @Override
        public void getResult(boolean bool) throws RemoteException {
            Log.d("AidlService","getResult="+bool);
        }

        @Override
        public void registListener(DemoCallback listener) throws RemoteException {
            mListener.register(listener);
        }

        @Override
        public void unregistListener(DemoCallback listener) throws RemoteException {
            mListener.unregister(listener);
        }
    };

    public static synchronized AidlService getInstance() {
        if (mService == null) {
            mService = new AidlService();
        }
        return mService ;
    }

    public static void notifyClient(DemoInfo mInfo) throws RemoteException {
        int count = mListener.beginBroadcast();
        for (int i = 0; i < count; i++) {
            DemoCallback broadcastItem = mListener.getBroadcastItem(i);
            if (broadcastItem != null) {
                try {
                    //发往客户端
                    broadcastItem.sendCtrlData(mInfo);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        //一定要记得finishBroadcast
        mListener.finishBroadcast();
    }
    @Override
    public IBinder onBind(Intent intent) {
        return stub;
    }
}

       在AndroidManifest.xml中定义下:

     

<service android:name="com.android.demo.AidlService">
      <intent-filter>
           <action android:name="com.android.demo.aidl" />
      </intent-filter>
</service>

       里面的action是供客户端绑定时的Intent所要设置的action。至此,服务端的AIDL相关方面就写好了,现在我们的客户端要去连接服务端。首先要做的就是把服务端刚才写的那些.AIDL复制到客户端,客户端路径要与服务端一致,如服务端是aidl.com.android.demo,那么客户端也要是aidl.com.android.demo。然后实现序列化得DemoInfo.java也要复制到客户端相同位置。现在我们来做连接操作。

package com.android.clinet;


import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;

import com.android.demo.DemoCallback;
import com.android.demo.DemoInterface;
import com.android.demo.DemoInfo;


/**
 * 服务绑定管理
 */
public class ServiceBindManage implements Handler.Callback{

    private final static String TAG = ServiceBindManage.class.getSimpleName();

    public static DemoInterface mManagerService = null;

    //全局事件服务
    private static ServiceBindManage mServiceBindManage = null;

    private DemoCallback mListener=new DemoCallback.Stub(){
        @Override
        public void sendCtrlData(DemoInfo status) throws RemoteException {
            Log.d(TAG,"mValue1="+status.getValue1()+",mValue2="+status.getValue2());
        }
    };

    private ServiceConnection mConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.d(TAG, "onServiceConnected");
            mManagerService = DemoInterface.Stub.asInterface(iBinder);
            try {
                mManagerService .registListener(mListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mManagerService.unregistListener(mListener);
            mManagerService = null;
        }
    };

    public static ServiceBindManage getInstance() {
        if (mServiceBindManage == null) {
            mServiceBindManage = new ServiceBindManage();
        }

        return mServiceBindManage;
    }

    public void bindService(Context ctx) {
        Log.d(TAG, "bindService");
        //绑定AIDL
        bindAidlService("com.android.demo.aidl",mConn);
    }


    private void bindAidlService(String action, ServiceConnection connent) {
        Log.d(TAG, "bindAidlService:Coon = " + connent);
        Intent intent = new Intent();
        intent.setAction(action);
        //服务端包名
        intent.setPackage("com.android.demo");
        MyApplication.getInstance().bindService(intent, connent, Context.BIND_AUTO_CREATE);
    }

    public void unBindService(Context ctx) {
        if(mManagerService != null){
            MyApplication.getInstance().unbindService(mConn);
            mManagerService = null;
        }

    }
}

       我们要与服务端绑定AIDL的时候,就调用ServiceBindManage.getInstance().bindService(this); 

       不需要时,就调用ServiceBindManage.getInstance().unBindService(this);

猜你喜欢

转载自blog.csdn.net/lhp1930/article/details/89418472