Android进程间通信——AIDL Binder连接池

当项目AIDL业务需求增多时,我们不可能无限制得创建Service,因此,针对这种情况,我们将所有得AIDL放在同一个Service中去管理。

在这种模式下,整个工作机制是这样得:每个业务模块创建自己得AIDL接口并实现此接口,这个时候不同业务模块之间不能有耦合的,所有实现细节我们要单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个Service就可以了,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。由此可见,Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免了重复创建Service的过程,它的工作原理如下图:

我们先看工程目录

下面我们Binder连接池的代码实现做一下说明。首先,我们提供了两个AIDL接口(IBookManager和IAuth)来模拟上面提到的多个业务模块都要使用AIDL的情况,其中IBookManager接口提供图书管理功能,IAuth接口提供获取用户信息功能,声明如下:

// IBookManager.aidl
package com.example.binderpool.aidl;
import com.example.binderpool.aidl.Book;
import com.example.binderpool.aidl.IOnNewBookArrivedListener;

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

interface IBookManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    List<Book> getBookList();
    void addBook(in Book book);
    void registerListener(IOnNewBookArrivedListener listener);
    void unregisterListener(IOnNewBookArrivedListener listener);
}
// IAuth.aidl
package com.example.binderpool.aidl;
import com.example.binderpool.aidl.User;

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

interface IAuth {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    User getCurrentUser();
}

接下来看两个接口的实现:

public class BookManagerImpl extends IBookManager.Stub {
    //CopyOnWriteArrayList支持并发读/写
    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
    //private CopyOnWriteArrayList<IOnNewBookArrivedListener> mListenerList = new CopyOnWriteArrayList<>();
    //当客户端进程终止后,RemoteCallbackList能够自动移除客户端所注册的listener。
    //RemoteCallbackList内部自动实现了线程同步的功能
    private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<>();

    @Override
    public List<Book> getBookList() throws RemoteException {
        return mBookList;
    }

    @Override
    public void addBook(Book book) throws RemoteException {
        mBookList.add(book);
    }

    @Override
    public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
//        if (!mListenerList.contains(listener)) {
//                mListenerList.add(listener);
//            } else {
//                Log.e(TAG, "listener already exists.");
//            }
//            Log.e(TAG, "registerListener, size:" + mListenerList.size());
        mListenerList.register(listener);
    }

    @Override
    public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
//        if (mListenerList.contains(listener)) {
//                mListenerList.remove(listener);
//                Log.e(TAG, "unregister listener succeed.");
//            } else {
//                Log.e(TAG, "not found, can not unregister.");
//            }
//
//            Log.e(TAG, "unregisterListener, current size:" + mListenerList.size());
        mListenerList.unregister(listener);
    }
}
package com.example.binderpool.aidl;

import android.os.RemoteException;

public class AuthImpl extends IAuth.Stub {

    @Override
    public User getCurrentUser() throws RemoteException {
        User user = new User(1, "ZOUJIN", "ZOUJIN6649", "https://dss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2075772401,2375569036&fm=179&app=42&f=JPEG?w=121&h=140&s=D7F5C46A051445C018C03E68030090F5");
        return user;
    }
}

下面为Binder连接池创建AIDL接口IBinderPool.aidl

// IBinderPool.aidl
package com.example.binderpool.aidl;

// 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 queryBinder(int binderCode);
}

接下来我们为Binder连接池创建远程Service并实现IBinderPool

public class BinderPool {
    private static final String TAG = "BinderPool";
    public static final int BINDER_NONE = -1;
    public static final int BINDER_BOOK_MANAGER = 0;
    public static final int BINDER_AUTH = 1;

    private Context mContext;
    private IBinderPool mBinderPool;
    private static volatile BinderPool sInstance;
    private CountDownLatch mConnectionBinderPoolCountDownLatch;

    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mBinderPool = IBinderPool.Stub.asInterface(iBinder);
//            try {
//                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
//            } catch (RemoteException e) {
//                e.printStackTrace();
//            }
            //将count值减1
            mConnectionBinderPoolCountDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBinderPool = null;
            connectionBinderPoolService();
        }
    };
//    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
//        @Override
//        public void binderDied() {
//            Log.e(TAG, "binder died.");
//            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
//            mBinderPool = null;
//            connectionBinderPoolService();
//        }
//    };

    private BinderPool(Context context) {
        mContext = context.getApplicationContext();
        connectionBinderPoolService();
    }

    public static BinderPool getInstance(Context context) {
        if (sInstance == null) {
            synchronized (BinderPool.class) {
                if (sInstance == null) {
                    sInstance = new BinderPool(context);
                }
            }
        }
        return sInstance;
    }


    public synchronized void connectionBinderPoolService() {
        mConnectionBinderPoolCountDownLatch = new CountDownLatch(1);
        Intent service = new Intent(mContext, BinderPoolService.class);
        mContext.bindService(service, mBinderPoolConnection, Context.BIND_AUTO_CREATE);
        try {
            //线程会挂起,直到count值为0才继续执行
            mConnectionBinderPoolCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public IBinder queryBinder(int binderCode) {
        IBinder binder = null;
        try {
            if (mBinderPool != null) {
                binder = mBinderPool.queryBinder(binderCode);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return binder;
    }

    public static class BinderPoolImpl extends IBinderPool.Stub {

        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder = null;
            switch (binderCode) {
                case BINDER_BOOK_MANAGER:
                    binder = new BookManagerImpl();
                    break;
                case BINDER_AUTH:
                    binder = new AuthImpl();
                    break;
                default:
                    break;
            }
            return binder;
        }
    }
}

我们在BinderPool内部绑定远程服务,绑定成功后,客户端就可以通过queryBinder方法去获取各自对应的Binder,拿到所需的Binder后,不同业务模块就可以进行各自的操作了。接下来我们看一下服务端的Service

public class BinderPoolService extends Service {
    private static final String TAG = "BinderPoolService";
    private Binder mBinderPool = new BinderPool.BinderPoolImpl();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind");
        return mBinderPool;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy");
    }
}

最后我们验证一下效果

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "BinderPoolActivity";
    Button getUserInfo;
    Button getBookList;
    ImageView headPic;
    TextView userName;
    TextView nickName;
    TextView bookListView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getUserInfo = findViewById(R.id.btn_get_user_info);
        getBookList = findViewById(R.id.btn_get_book_list);
        headPic = findViewById(R.id.headPic);
        userName = findViewById(R.id.username);
        nickName = findViewById(R.id.nickname);
        bookListView = findViewById(R.id.bookList);

        getUserInfo.setOnClickListener(this);
        getBookList.setOnClickListener(this);

    }


    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_get_user_info:
                getUserInfo();
                break;
            case R.id.btn_get_book_list:
                getBookList();
                break;

        }
    }

    private void getBookList() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                BinderPool binderPool = BinderPool.getInstance(getApplicationContext());
                IBinder bookManagerBinder = binderPool.queryBinder(BinderPool.BINDER_BOOK_MANAGER);
                IBookManager bookManager = BookManagerImpl.asInterface(bookManagerBinder);

                Log.e(TAG, "visit IBookManager");
                Book book1 = new Book(1, "Android");
                try {
                    bookManager.addBook(book1);
                    Log.e(TAG, "add book:" + book1.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }

                try {
                    final List<Book> bookList = bookManager.getBookList();
                    Log.e(TAG, "get book list:" + bookList.toString());
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            bookListView.setVisibility(View.VISIBLE);
                            bookListView.setText(bookList.toString());
                        }
                    });
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void getUserInfo() {
        Log.e(TAG, "打印-->getUserInfo()");
        new Thread(new Runnable() {
            @Override
            public void run() {
                BinderPool binderPool = BinderPool.getInstance(getApplicationContext());
                IBinder authBinder = binderPool.queryBinder(BinderPool.BINDER_AUTH);
                IAuth auth = AuthImpl.asInterface(authBinder);
                Log.e(TAG, "visit IAuth");
                try {
                    final User user = auth.getCurrentUser();
                    Log.e(TAG, "get user info:" + user.toString());

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            userName.setText(user.getUserName());
                            nickName.setText(user.getNickName());
                            Glide.with(MainActivity.this).load(user.getHeadPic()).into(headPic);
                        }
                    });
                } catch (RemoteException e) {
                    e.printStackTrace();
                }


            }
        }).start();
    }

}

效果如下:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值