Android中AIDL的使用詳解,如何發起回調?


這是百度面試官問的一個問題,當時沒答上來。我們知道AIDL底層是基於Binder機制通信的,而Binder本身是C/S架構的。Activity寫個AIDL接口可以實現跟Service的通信,那么Service如何主動回調或者主動推送消息到Activity呢?

定義通信接口

這個接口是Activity發數據給Service用的,addPerson會在Service中的List中新增一個數據,getPersonList返回Person列表。registerCallback注冊回調對象,等一會兒會說。

package com.billshen.offerlearn.service;
import com.billshen.offerlearn.service.IPersonCallBack;
interface IPerson {
    void addPerson(String name);
    List<String> getPersonList();
    void registerCallback(IPersonCallBack cb);
    void unregisterCallback(IPersonCallBack cb);
}

IPersonCallBack.aidl這個接口是Service主動回調Activity用的,用於獲取Activity中的時間。

package com.billshen.offerlearn.service;
interface IPersonCallBack {
    String getTime();
}

在AndroidManifest中定義service為另一個進程,並指明action

<service
    android:name="com.billshen.offerlearn.service.AIDLService"
    android:enabled="true"
    android:exported="true"
    android:process=":aidl_service">
    <intent-filter>
        <action android:name="com.aidl.person" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</service>

定義完成后,在AS中build一下,編譯器會自動為我們生成binder抽象對象,當然你也可以自己寫。

IPerson是個interface繼承於IInterface

 

內部包含我剛才在AIDL里面聲明的四個方法。

 

還有三個內部靜態類Default,Stub和Proxy。其中Stub交給服務方實現,Proxy交給客戶端持有。Proxy主要是怎么往內核空間寫數據和拿數據,Default是默認實現,基本不用。

 

 

 

 

 

實現具體方法

編譯器為我們生成的IPerson.java文件中有個Stub()內部靜態類,這是個抽象類,具體實現需要我們自己去寫。RemoteCallbackList是一個回調對象列表,可以把Service想象成一個服務器,多個Activity為客戶端。Service在建立連接的時候保存了客戶端的回調對象。

public class AIDLService extends Service {
    private String TAG = AIDLService.class.getSimpleName();
    private RemoteCallbackList<IPersonCallBack> iPersonCallBacks = new RemoteCallbackList<>();//回調對象列表
    List<String> mPersons = new ArrayList<>();

    public AIDLService() {
        mPersons.add("初始人");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: " + mPersons);
        BroadcastThread broadcastThread = new BroadcastThread();
        broadcastThread.start();
        return new IPerson.Stub() {
            @Override
            public void addPerson(String name) throws RemoteException {
                mPersons.add(name);
            }

            @Override
            public List<String> getPersonList() throws RemoteException {
                return mPersons;
            }

            @Override
            public void registerCallback(IPersonCallBack cb) throws RemoteException {
                iPersonCallBacks.register(cb);//注冊回調對象
            }

            @Override
            public void unregisterCallback(IPersonCallBack cb) throws RemoteException {
                iPersonCallBacks.unregister(cb);//反注冊回調對象
            }
        };
    }

    class BroadcastThread extends Thread {
        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000);
                    int len = iPersonCallBacks.beginBroadcast();//開始發送廣播
                    for (int i = 0; i < len; i++) {//遍歷回調對象,將拿回來的數據打印再控制台上
                        Log.i(TAG, "run: " + iPersonCallBacks.getBroadcastItem(0).getTime());
                    }
                    iPersonCallBacks.finishBroadcast();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 Activity中實現客戶端的回調函數和開啟新線程不斷讓Service增加Person並拿回數據顯示在TextView上。

public class AIDLActivity extends BaseMvpActivity {

    IPerson iPerson = null;
    TextView resultTv;
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            try {
                resultTv.setText(iPerson.getPersonList().toString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            super.handleMessage(msg);
        }
    };

    @Override
    public void initView() {
        Log.i(TAG, "initView: ");
        resultTv = findViewById(R.id.result_tv);
    }

    @Override
    public void initData() {
        Log.i(TAG, "initData: ");
        Intent intent = new Intent();
        intent.setPackage("com.billshen.offerlearn");
        intent.setAction("com.aidl.person");
        ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iPerson = IPerson.Stub.asInterface(service);
                IPersonCallBack iPersonCallBack = new IPersonCallBack.Stub() {
                    @Override
                    public String getTime() throws RemoteException {
                        //回調函數,返回時間給服務端
                        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        return df.format(System.currentTimeMillis());
                    }
                };
                try {
                    iPerson.registerCallback(iPersonCallBack);//在Service中注冊回調
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                new PersonThread().start();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);
    }

    class PersonThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    iPerson.addPerson("person" + i);
                    Thread.sleep(1000);
                    mHandler.sendEmptyMessage(0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_aidl;
    }

    @Override
    public void showLoading() {

    }

    @Override
    public void hideLoading() {

    }

    @Override
    public void refreshView() {

    }

    @Override
    public void onError(String errMessage) {

    }
}

運行結果

Activity客戶端結果

Service服務端結果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM