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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章