• 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服务端结果

  • 相关阅读:
    102. 教程:重装谷歌浏览器的教程
    IGBT知识普及
    [刷机资源] 荣耀8 E5 B391 V2 ROM集合 Xposed DPI调整等 N多自定义功能 Kangvip@HRT( 2017-9-28)
    ITPUB附件下载免输验证码 (实际下载地址的规则)
    花生壳内网穿透不再支持国外IP!
    golang 如何开发windows窗口界面
    golang 热重启
    强化go get命令
    go mod get go-git timeout
    golang单一职责原则接口设计例子
  • 原文地址:https://www.cnblogs.com/billshen/p/13440309.html
Copyright © 2020-2023  润新知