The same process within the implementation of interface back is very simple, here do not do the narrative, this article is mainly about the implementation of cross-process interface back. One way to communicate across processes is to use AIDL, but AIDL communication can only enable clients to access servers and actively obtain Binder objects. If the server changes, the client cannot be notified in time. The problem of notifying clients of changes on the server can now be solved by AIDL cross-process interface fallback.

Google provides RemoteCallbackList to manage the IInterface. public class RemoteCallbackList

Start by defining two AIDL files:

  1. ITestCallBack.aidl

    interface ITestCallBack {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void onTagValid(in String tag);
    
    }
    Copy the code
  2. ITestInterface. Aidl In the registration and anti-ancestor volume methods, the object of the ITestCallBack is passed in

    interface ITestInterface {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
         boolean isTagValid(in String tag);
    
         void registerCallback(in String tag, in ITestCallBack callback);
    
         void unRegisterCallback(in String tag, in ITestCallBack callback);
    }</span> 
    Copy the code

Server:

Create a Service and define the RemoteCallbackList collection in the Service, implement ITestInterface.Stub, registerCallback, and unRegisterCallback. Register and unregister ITestCallBack objects into RemoteCallbackList, respectively. RemoteCallbackList provides methods to get registered IInterface objects.

{@link java.util.observable} is used to batch handle interface callback objects. If you ensure that only one client will bind to the service, Just save an IMyAidlInterfaceCallback. RemoteCallbackList public void callBack() {if (mCallBacks == null) {return; } int num = mCallBacks.beginBroadcast(); for (int i = 0; i < num; i++) { try { mCallBacks.getBroadcastItem(i).onTagValid("congratulation callback success " + tag); } catch (RemoteException e) { e.printStackTrace(); }} / / must be used after finsh, otherwise the next execution beginBroadcast throws an IllegalStateException abnormal mCallBacks. FinishBroadcast (); }Copy the code

In isTagValid, the callBack method can be called to iterate through the registered interface object, and the server can be called to notify the client when the server changes. You can modify it based on the actual method.

In the onBind method of the service, return the itestInterface.stub object and wait for the client to bind the server.

Here is the code for the server Service:

public class TestService extends Service { private RemoteCallbackList<ITestCallBack> mCallBacks = new RemoteCallbackList<>(); private String tag = "hy"; public TestService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return iTestInterface; } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } ITestInterface.Stub iTestInterface = new ITestInterface.Stub() { @Override public boolean isTagValid(String tag) throws RemoteException { if (tag.equals(TestService.this.tag)) { callBack(); return true; } return false; } @Override public void registerCallback(String tag, ITestCallBack callback) throws RemoteException { if (null ! = mCallBacks && null ! = callback) { mCallBacks.register(callback); } } @Override public void unRegisterCallback(String tag, ITestCallBack callback) throws RemoteException { if (null ! = mCallBacks && null ! = callback) { mCallBacks.unregister(callback); }}}; public void callBack() { if (mCallBacks == null) { return; } int num = mCallBacks.beginBroadcast(); for (int i = 0; i < num; i++) { try { mCallBacks.getBroadcastItem(i).onTagValid("congratulation callback success " + tag); } catch (RemoteException e) { e.printStackTrace(); } } mCallBacks.finishBroadcast(); }}Copy the code

Client:

The first thing the client needs to do is bind the server to implement AIDL communication, and create bind buttons, unbind buttons, and active access communication buttons on the client side. The isTagValid method that implements the iTestInterface object in the communication button to actively fetch information can actively fetch information from the server (the server calls the callBack method in the isTagValid method).

Client code:

public class MainActivity extends AppCompatActivity { private String tag = "hy"; private ITestInterface iTestInterface; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iTestInterface = ITestInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { iTestInterface = null; }}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindService(); ((Button) findViewById(R.id.buttonregister)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { iTestInterface.registerCallback(tag, new ITestCallBack.Stub() { @Override public void onTagValid(String tag) throws RemoteException { Log.e("test", "registerCallback: " + tag); }}); } catch (RemoteException e) { e.printStackTrace(); }}}); ((Button) findViewById(R.id.buttonunregister)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { iTestInterface.unRegisterCallback(tag, new ITestCallBack.Stub() { @Override public void onTagValid(String tag) throws RemoteException { } }); } catch (RemoteException e) { e.printStackTrace(); }}}); ((Button) findViewById(R.id.buttonisvalid)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { iTestInterface.isTagValid(tag); } catch (RemoteException e) { e.printStackTrace(); }}}); } private void bindService() { Intent intent = new Intent(); intent.setAction("com.example.heyang.myapplication.TestService"); intent.setPackage("com.example.heyang.myapplication"); boolean success = bindService(intent, connection, Context.BIND_AUTO_CREATE); if (success) { Log.e("test ", "bindService OK"); } else { Log.e("test ", "bindService Fail"); } } @Override protected void onDestroy() { super.onDestroy(); unBindeService(); } private void unBindeService() { try { unbindService(connection); } catch (Exception e) { e.printStackTrace(); }}}Copy the code