- 上一篇已经介绍了进程间通讯的几种方式,并且着重说明了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就实现完成了,当然只是最普通的入门,并且也是存在问题的,具体问题以及优化在下一篇文章中在进行说明。