天天看点

IPC机制---04 Android中的IPC通讯方式(B)

  • 上一篇已经介绍了进程间通讯的几种方式,并且着重说明了Messenger的方式。简单说一下Messenger的优缺点吧。
    • 底层基于AIDL,系统为我们做了封装,使用简单方便
    • 以串行的方式处理客户端发过来的数据,如果大量的消息同时发送到服务端,也只能一个个处理,并发量大的话,Messenger就不太合适了
    • Messenger作用主要是为了传递数据,如果要跨进程调用服务端的方法,就无法做到了
  • 下面介绍一下使用AIDL进行跨进程通信的方法
    • 服务端
      • 创建一个Service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service实现这个AIDL接口即可
    • 客户端
      • 绑定Service,绑定成功后,将服务端返回的IBinder对象转换成AIDL接口所属的类型,接着就可以调用AIDL的方法了
  • 几个注意点
    • AIDL所支持的数据类型
      • 基本数据类型  short除外,因为short不支持parcelable的序列化
      • String和CharSequence
      • List,只支持ArrayList,并且里面的每个元素实现Parcelable
      • Map,只支持HashMap,其Key和Value也必须实现Parcelable
      • Parcelable,所有实现了这个接口的对象
      • AIDL,所有的AIDL接口本身也可以在AIDL文件中使用
    • 另外一个需要注意的地方,就是如果AIDL文件中用到了自定义的Parcelable对象,必须新建一个和他同名的AIDL文件,并为他声明为parcelable类型。
    • AIDL中除了基本数据类型,其它类型的参数必须标上方向,in -输入型参数 ,out - 输出型参数 ,inout - 输入输出型参数。
    • 区别于传统接口,AIDL接口只支持方法,不支持声明静态常量
    • 讲aidl文件或实体类拷贝到客户端时,切记要保持报名一致,因此建议在server端进行开发的时候就把他们包处理好,尽量放到同一个包中
  • demo如下
    • AIDL文件的声明
      • 暴露接口的声明
      • // IBookManager.aidl
        package com.happy.ipc.server;
        import com.happy.ipc.server.domain.Book;
        // Declare any non-default types here with import statements
        
        interface IBookManager {
        
           int getBookCount();
        
           List<Book> addBook(in Book book);
        
        }
                   
      • 自定义对象的AIDL的声明
      • // Book.aidl
        package com.happy.ipc.server.domain;
        
        parcelable Book;
                   
    • Server端service的实现
      • package com.happy.ipc.server.service;
        
        import android.app.Service;
        import android.content.Intent;
        import android.os.IBinder;
        import android.os.RemoteException;
        
        import com.happy.ipc.server.IBookManager;
        import com.happy.ipc.server.domain.Book;
        
        import java.util.ArrayList;
        import java.util.List;
        
        public class BookService extends Service {
        
            private ArrayList<Book> bookList = new ArrayList<>();
        
            public BookService() {
            }
        
            @Override
            public void onCreate() {
                super.onCreate();
                bookList.add(new Book(1, "红楼梦"));
                bookList.add(new Book(2, "三国演义"));
            }
        
            @Override
            public IBinder onBind(Intent intent) {
                return mBinder;
            }
        
            private IBinder mBinder = new IBookManager.Stub() {
                @Override
                public int getBookCount() throws RemoteException {
                    return bookList.size();
                }
        
                @Override
                public List<Book> addBook(Book book) throws RemoteException {
                    bookList.add(book);
                    return bookList;
                }
            };
        
        }
                   
    • client端的实现
      • 首先将IBookManager.aidl Book.aidl Book.java拷贝到客户端
      • 页面提供两个按钮,一个查询bookCount,另外一个添加图书,并返回当前所有BookList,activity代码如下
      • package com.happy.ipc.client;
        
        import android.content.ComponentName;
        import android.content.Context;
        import android.content.Intent;
        import android.content.ServiceConnection;
        import android.os.IBinder;
        import android.os.RemoteException;
        import android.support.v7.app.AppCompatActivity;
        import android.os.Bundle;
        import android.util.Log;
        import android.view.View;
        import android.widget.Button;
        
        import com.happy.ipc.server.IBookManager;
        import com.happy.ipc.server.domain.Book;
        
        import java.util.List;
        
        public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        
            private static final String TAG = "MainActivity";
        
            private Button mGetCount;
        
            private Button mAddBook;
        
            private IBookManager mBookManager;
        
            private ServiceConnection conn = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    mBookManager = IBookManager.Stub.asInterface(service);
                }
        
                @Override
                public void onServiceDisconnected(ComponentName name) {
                    mBookManager = null;
                }
            };
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        
                mGetCount = (Button) this.findViewById(R.id.getCount);
                mAddBook = (Button) this.findViewById(R.id.addBook);
        
                mGetCount.setOnClickListener(this);
                mAddBook.setOnClickListener(this);
        
                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.happy.ipc.server", "com.happy.ipc.server.service.BookService"));
                bindService(intent, conn, Context.BIND_AUTO_CREATE);
        
            }
        
            @Override
            public void onClick(View v) {
                switch (v.getId()) {
                    case R.id.getCount:
                        if (mBookManager != null) {
                            try {
                                int count = mBookManager.getBookCount();
                                Log.i(TAG, "count = " + count);
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        }
                        break;
                    case R.id.addBook:
                        if (mBookManager != null) {
                            try {
                                List<Book> bookList = mBookManager.addBook(new Book(3, "西游记"));
                                Log.i(TAG, "bookList = " + bookList.toString());
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        }
                        break;
                }
            }
        
            @Override
            protected void onDestroy() {
                super.onDestroy();
                unbindService(conn);
            }
        }
                   
      • 这样,通过点击按钮,查看log如下
      • 03-09 11:18:30.099 3155-3155/com.happy.ipc.client I/MainActivity: count = 2
        03-09 11:18:31.739 3155-3155/com.happy.ipc.client I/MainActivity: bookList = [Book{bookName='红楼梦', id=1}, Book{bookName='三国演义', id=2}, Book{bookName='西游记', id=3}]
        03-09 11:18:33.379 3155-3155/com.happy.ipc.client I/MainActivity: count = 3
                   
  • 这样,一个简单的AIDL就实现完成了,当然只是最普通的入门,并且也是存在问题的,具体问题以及优化在下一篇文章中在进行说明。