在android中进程与之间的通信最常用的是基于binder的Aldl(在ALDL中进行了一部分封装),所以使用起来比较方便
首先来粘贴自己写的一个aidl的demo ,基于此进行源码的探究:
首先在android中service—-client之间的通信
ok 下面 来看代码 :
Service:
Book.aidl:
// Book.aidl
package com.example.ipcclient;
// Declare any non-default types here with import statements
// declare class of book for aidl
parcelable Book;
IBookManager.aidl:
// IBookManager.aidl
package com.example.ipcclient;
// Declare any non-default types here with import statements
import com.example.ipcclient.Book;
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);
}
Book.java:
package com.example.ipcclient;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable{
public String bookId;
public String bookName;
public Book(String bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
public String getBookId() {
return bookId;
}
public void setBookId(String bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readString();
bookName = in.readString();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bookId);
dest.writeString(bookName);
}
}
IBookService:
package com.example.ipcclient;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class IBookservice extends Service{
private ArrayList<Book> books;
@Nullable
@Override
public IBinder onBind(Intent intent) {
books = new ArrayList<>();
return binder;
}
IBinder binder = new IBookManager.Stub(){
@Override
public List<Book> getBookList() throws RemoteException {
if (books.size() == 0){
return null;
}
return books;
}
@Override
public void addBook(Book book) throws RemoteException {
books.add(book);
}
};
}
Client
service下的aidl Book.java 复制到clent下 <注意包名要一致>
MainActivity.java
package com.example.ipcservice;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.ipcclient.Book;
import com.example.ipcclient.IBookManager;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private int index;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManager = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IBookManager iBookManager;
private TextView txt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
bindService();
}
private void initView() {
Button btn = findViewById(R.id.btn);
txt = findViewById(R.id.txt);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
txt.setText("");
Book book = new Book(String.valueOf(index), "java 基础");
index++;
try {
iBookManager.addBook(book);
List<Book> bookList = iBookManager.getBookList();
for (int i = 0;i < bookList.size();i++){
txt.append(bookList.get(i).toString() + "---");
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void bindService() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.ipcclient",
"com.example.ipcclient.IBookservice"));
bindService(intent,conn, Context.BIND_AUTO_CREATE);
}
}
源码分析
这就是完整代码,在Service下注册服务,然后build之后会在build/generated/source/aidl/debug下生成IBookManager.java
这个是核心的代码
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /Users/houruixiang/myspace/DesignAndroid/ClientIpc/src/main/aidl/com/example/ipcclient/IBookManager.aidl
*/
package com.example.ipcclient;
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.ipcclient.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.example.ipcclient.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.ipcclient.IBookManager interface,
* generating a proxy if needed.
*/
public static com.example.ipcclient.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.ipcclient.IBookManager))) {
return ((com.example.ipcclient.IBookManager)iin);
}
return new com.example.ipcclient.IBookManager.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.ipcclient.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.example.ipcclient.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.ipcclient.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.ipcclient.IBookManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public java.util.List<com.example.ipcclient.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.ipcclient.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.ipcclient.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.ipcclient.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public java.util.List<com.example.ipcclient.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.ipcclient.Book book) throws android.os.RemoteException;
}
在service下IBookService中实例化IBookManager的静态内部类,初始化服务中自己顶方法体,以备client来调用,然后在IBookService中的onBind方法中返回改Service的IBinder实例对象:
IBinder binder = new IBookManager.Stub(){
@Override
public List<Book> getBookList() throws RemoteException {
if (books.size() == 0){
return null;
}
return books;
}
@Override
public void addBook(Book book) throws RemoteException {
books.add(book);
}
};
然后在client中的MainActivity中跨进程绑定该service,在bindservice中获取初始化目标方法后的IBookManager的实例化IBinder—Stub
private void bindService() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.ipcclient",
"com.example.ipcclient.IBookservice"));
bindService(intent,conn, Context.BIND_AUTO_CREATE);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManager = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
ok,现在获取到service端传来的binder对象<目标方法的方法体已经初始化完毕>,下面需要根据其binder来获取IBookManager对象来传入参数,来跨进程调用service端实例化方法
但是在IBookManager中通过binder只能获取其代理对象:
public static com.example.ipcclient.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.ipcclient.IBookManager))) {
return ((com.example.ipcclient.IBookManager)iin);
}
return new com.example.ipcclient.IBookManager.Stub.Proxy(obj);
}
在java中代理的使用比较频繁,那么我们同样使用IBookManager的代理对象Proxy来进行调用其方法:
在client的MainActivity中我们这样调用:
@Override
public void onClick(View v) {
txt.setText("");
Book book = new Book(String.valueOf(index), "java 基础");
index++;
try {
iBookManager.addBook(book);
List<Book> bookList = iBookManager.getBookList();
for (int i = 0;i < bookList.size();i++){
txt.append(bookList.get(i).toString() + "---");
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
这样直接走到IBookManager的代理的addBook(Book book)和getBookList()方法中:
private static class Proxy implements com.example.ipcclient.IBookManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public java.util.List<com.example.ipcclient.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.ipcclient.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.ipcclient.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.ipcclient.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
上面的代码就是调用poxy的源码,其中mRemote就是service端传来的binder,即service端的IBookManager的静态内部类Stub,其中核心代码:
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
就是参数data传入,然后通过transact调用Service中的onTransact方法;下面看源码
* Default implementation rewinds the parcels and calls onTransact. On
* the remote side, transact calls into the binder to do the IPC.
*/
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
由以上代码可以知道,在transact中调用到onTransact(code, data, reply, flags);
那么继续看service下的IBookManager中Stub的onTransact:
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.ipcclient.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.example.ipcclient.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.ipcclient.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
在Service端的onTransact中进行reply的写入;
到这里大概明白了,transact和onTransact中data是client中参数的传入,如果方法有返回,会有reply的写入并返回在result中;
那么继续看服务端代码IBookManger:
@Override public java.util.List<com.example.ipcclient.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.ipcclient.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.ipcclient.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.ipcclient.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
是不是 和service交互之后data作为参数传入,reply写入结果,如果方法需要返回,从reply中写入result返回;
android IPC比较晦涩,但是理清的思路还是ok;有想法的朋友可以去看底层的实现
感谢阅读