跨应用的aidl异步回调

问题出现

最近工作遇到的问题,之前通过绑定系统签名包服务调用静默安装接口,同步获取到结果,最后将结果返回到服务器。

但是新的android系统版本出来后,静默安装接口无效了,后来找到了一个新的方案代替,还是通过aidl的方式来实现,但是执行结果只能异步获取到。


解决方案提出

通过添加一个回调接口,执行结果异步回调给调用方


疑问

跨进程的回调,怎么保证调用方和被调用方的回调接口一致?

RemoteCallbackList的使用。

看注释,Takes care of the grunt work of maintaining a list of remote interfaces,
 * typically for the use of performing callbacks from a
 * {@link android.app.Service} to its clients.

管理包含了远程接口的列表,这些接口通常是用来从Service回调给调用的客户端。


/**
 * Takes care of the grunt work of maintaining a list of remote interfaces,
 * typically for the use of performing callbacks from a
 * {@link android.app.Service} to its clients.  In particular, this:
 *
 * 
    *
  • Keeps track of a set of registered {@link IInterface} callbacks, * taking care to identify them through their underlying unique {@link IBinder} * (by calling {@link IInterface#asBinder IInterface.asBinder()}. *
  • Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to * each registered interface, so that it can be cleaned out of the list if its * process goes away. *
  • Performs locking of the underlying list of interfaces to deal with * multithreaded incoming calls, and a thread-safe way to iterate over a * snapshot of the list without holding its lock. *
* *

To use this class, simply create a single instance along with your * service, and call its {@link #register} and {@link #unregister} methods * as client register and unregister with your service. To call back on to * the registered clients, use {@link #beginBroadcast}, * {@link #getBroadcastItem}, and {@link #finishBroadcast}. * *

If a registered callback's process goes away, this class will take * care of automatically removing it from the list. If you want to do * additional work in this situation, you can create a subclass that * implements the {@link #onCallbackDied} method. */ public class RemoteCallbackList { /*package*/ ArrayMap mCallbacks = new ArrayMap(); private Object[] mActiveBroadcast; private int mBroadcastCount = -1; private boolean mKilled = false; private final class Callback implements IBinder.DeathRecipient { …… }


方案测试


编写Service的aidl 接口,并另外新建一个aidl文件来写回调接口。

import com.demo.service.IServiceCallback;

interface ServiceDemoAidl {

	boolean isInited();
	
	void registerCallback(IServiceCallback cb);
    void sendMSGCallback(IServiceCallback cb);
    
}  

/**
 * a callback interface used by dvbService to send
 * synchronous notifications back to its clients.  Note that this is a
 * one-way interface so the server does not block waiting for the client.
 */
oneway interface IServiceCallback {
	
    
    /*
	 * handler search message from service
	 */
    void handlerSearchEvent(int msgID, in List strList);
}

绑定Service时,

 @SuppressLint("NewApi")
    private final ServiceDemoAidl.Stub mBinder = new ServiceDemoAidl.Stub() {

        @Override
        public void registerCallback(IServiceCallback cb) throws RemoteException {
            ……

        }

        @Override
        public void sendMSGCallback(IServiceCallback cb) throws RemoteException {
           ……
        }

    };

在registerCallBack里,我们使用RemoteCallBackList来注册回调接口。
 static RemoteCallbackList mCallbacks = new RemoteCallbackList();

  @Override
        public void registerCallback(IServiceCallback cb) throws RemoteException {
            // TODO Auto-generated method stub
            if (cb != null) {
                Log("mCallbacks==null?" + (mCallbacks == null) + "   cb==null?" + (cb == null));

                if (mCallbacks.getRegisteredCallbackCount() == 0) {

                    Log("mCallbacks has been killed,reregister");
                    mCallbacks = new RemoteCallbackList();
                    
                }

            }

        }


在这个异步回调的接口中我们使用handler来模拟异步执行的情况
 @Override
        public void sendMSGCallback(IServiceCallback cb) throws RemoteException {
            // TODO Auto-generated method stub
            //            if (cb != null)
            //                mCallbacks.unregister(cb);

            Log(" mHandler.sendEmptyMessage(Msg.HIDE_MSG);");

            if (System.currentTimeMillis() % 2 == 0)
                mHandler.sendEmptyMessage(Msg.HIDE_MSG);
            else
                mHandler.sendEmptyMessage(Msg.SHOW_MSG);

        }

定义Handler
 private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

           
                sendMsg(msg.what);
          
        }
    };

 public void sendMsg(int msgId) {

        
        ArrayList strList = new ArrayList();

        if (msgId == Msg.SHOW_MSG) {
            strList.add("ServiceDemo show msg"); // tip message
        } else {
            strList.add("ServiceDemo hide msg"); // tip message
        }

        // Broadcast to all clients the new value.
        final int N = mCallbacks.beginBroadcast();


        try {
            for (int i = 0; i < N; i++) {
                mCallbacks.getBroadcastItem(i).handlerSearchEvent(msgId, strList);
            }

        } catch (RemoteException e) {

            Log("sendMsg Exception");
        }

        mCallbacks.finishBroadcast();
    }

回调接口的调用需要用 mCallbacks.getBroadcastItem(i).handlerSearchEvent(msgId, strList)的方式来执行。

Service端已经写完,开始写Client端。

service 端的两个aidl文件都直接复制到Client客户端。

进入Client客户端是绑定服务:先初始化该连接,然后绑定。

 // 初始化service
    private void initConnection() {
        Log("initConnection");
        mConnection = new ServiceConnection() {

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                // TODO Auto-generated method stub
                mService = ServiceDemoAidl.Stub.asInterface(service);
                try {
                    if (mService.isInited()) {
                        mService.registerCallback(mCallback);//注册回调接口
                        Log("init成功.注册回调接口");
                    } else {
                        Log("init未成功.注册回调接口");
                        exitService(); // 
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                mService = null;
            }

        };
    }

    private IServiceCallback mCallback = new IServiceCallback.Stub() {

        @Override
        public void handlerSearchEvent(int msgID, List strList) throws RemoteException {

            Log("IServiceCallback  handlerSearchEvent");

           ……
        }
    };


  private void startService() {
        Intent intent = new Intent("action");
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }



绑定成功后,通过点击事件来调用异步回调接口。

  Button button = (Button) findViewById(R.id.bt);
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                try {

                    Log("unregister,mService & mCallback==" + (mService == null) + "   " + (mCallback == null));
                    mService.sendMSGCallback(mCallback);//触发回调

                } catch (RemoteException e) {

                    Log("unregister,exception:" + e);
                }
            }
        });




总结

实现主要使用RemoteCallBackList来管理回调接口。








你可能感兴趣的:(Android)