Binder Connection Pool - teaches you how to better manage your AIDL

AIDL is a very common IPC method in Android development. Normally, each AIDL service corresponds to one service.If we have 20 AIDL services, don't we start 20 services?Not to mention the usage of mobile resources by 20 services, just code management is messy.

Is there a good solution?Of course, that's what this article is about - the Binder connection pool.The Binder link pool essentially manages other AIDLs through one AIDL, requiring only one service to provide all AIDL services.

First, look at the demo I wrote. First, the demo directory structure:

app is client side, ServiceDemo is server side.

There are three AIDl files:
IBinderPool:Binder pool, returns different Binders based on int value

// IBinderPool.aidl
package com.servicedemo.server;

// Declare any non-default types here with import statements

interface IBinderPool {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    IBinder getBinder(int type);
}

IBinderA:A Service

// IBinderA.aidl
package com.servicedemo.server;

// Declare any non-default types here with import statements

interface IBinderA {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void methodA(String paramA);
}

IBinderB:B service, code and A similar, no longer posted, you can just see demo

BinderAImpl and BinderBImpl are implementations of IBinderA and IBinderB, where A code is:

public class BinderAImpl extends IBinderA.Stub{
    @Override
    public void methodA(String paramA) throws RemoteException {
        Log.e("lzw","methodA");
    }
}

BinderBImpl is similar to BinderAImpl in that the code refers to demo.

Here's how BinderPoolService is implemented: Return different Binders based on different type s

public class BinderPoolService extends Service {
    public BinderPoolService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new IBinderPool.Stub() {
            @Override
            public IBinder getBinder(int type) throws RemoteException {
                // Return BinderAImpl or BinderBImpl based on different type s
                switch (type) {
                    case 1:
                        return new BinderAImpl();
                    default:
                        return new BinderBImpl();
                }
            }
        };
    }

}

See how the client calls:
1. First encapsulate a tool class, BinderPoolTool:

public class BinderPoolTool {

    private Context c;
    private static BinderPoolTool INSTANCE;
    private IBinderPool pool;

    private ServiceConnection mBinderConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("lzw","onServiceConnected");
            pool = IBinderPool.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("lzw","onServiceDisconnected");
        }
    };

    private BinderPoolTool(Context c){
        this.c = c.getApplicationContext();
        bindAidl();
    }

    public static BinderPoolTool getInstance(Context c){
        if(INSTANCE == null){
            synchronized (ServiceConnection.class){
                if(INSTANCE == null){
                    INSTANCE = new BinderPoolTool(c);
                }
            }

        }
        return INSTANCE;
    }

    // Bind BinderPool Service
    private void bindAidl(){
        Intent i = new Intent("com.binderpool");
        i.setPackage("com.servicedemo.server");
        c.bindService(i,mBinderConnection,Context.BIND_AUTO_CREATE);
    }

    // Exposed method to get Binder, calling the getBinder method of the BinderPool service to return Binder
    public IBinder getBinder(int type){
        IBinder binder = null;
        try {
            binder = pool.getBinder(type);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return binder;
    }

}

The code is concise, and the tool class is a single example, binding the BinderPool service in the constructor to get an instance of BinderPool.The getBinder method is exposed, and the internal implementation is to call an instance of BinderPool to call its getBinder to get a different Binder.

Let's take a look at the call to client:

public class MainActivity extends AppCompatActivity {

    private BinderPoolTool pool;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Get an instance of BinderPoolTool
        pool = BinderPoolTool.getInstance(this);
    }

    public void onClick(View v){
        switch (v.getId()){
            case R.id.btn3:
                // Be sure to use IBinderA.Stub.asInterface to convert the Binder that the pool.getBinder gets here
                // Type cast cannot be performed directly
                IBinderA a = IBinderA.Stub.asInterface(pool.getBinder(1));
                try {
                    a.methodA("");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
            case R.id.btn4:
                IBinderB b = IBinderB.Stub.asInterface(pool.getBinder(0));
                try {
                    b.methodB("");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }

    }
}

Simply, once you get an instance of a tool class, get the corresponding instance through the getBinder method, and call the corresponding Binder method.

Code address: https://github.com/dreamlizhengwei/BinderPoolDemo

Keywords: Android Mobile github

Added by adeelzia on Tue, 16 Jul 2019 19:02:00 +0300