android IPC 机制

p, li { white-space: pre-wrap; }

IPC即Inter-Process Communication,含义为进程间的通信或者跨进程通信,是指两个进程之间进行数据交换的过程。

android 中使用多进程

android中使用多进程很“简单”,简单到只需要一行代码就可以开启一个进程。但是真正要用好多进程还是不简单的。android中使用进程只需要在manfiest中进行申明,形式如下:

<activity
android:name="com.reoger.cc.hello"
android:process = "com.reoger.cc.hello.word"/>

当然,也可以process的属性也可以设为以":"开始,例如

android:process =":remote"

表示运行在当前activity或者service的包名+.remote

Binder基础

什么是binder?

Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,他的设备驱动是/dev/binder,该通信方式在Linux中没有。从Android Framework角度说,Binder是ManagerService的桥梁。从Android应用层角度来说,Binder是客户端和服务端调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。

使用基础

本例将用aidl实现进程间的通信,同时服务端将会每隔5s给订阅图书信息的人发一条信息,同时客户端也可以其进行订阅和取消订阅操作。
首先先给出使用实例的整体框架视图,如图:

11-00-49.jpg

首先新建一个序列化的bean对象,命名为Book.java。

public class Book implements Parcelable {

private int id;
private String bookName;

public Book(int id, String bookName) {
this.id = id;
this.bookName = bookName;
}

@Override
public String toString() {
return "Book{" +
"id=" + id +
", bookName='" + bookName + '\'' +
'}';
}

protected Book(Parcel in) {
id = in.readInt();
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.writeInt(id);
dest.writeString(bookName);
}
}

然后新建aidl文件夹,并在里面添加Book.aidl文件,代码为:

// Book.aidl.aidl
package reoger.hut.test2;
parcelable Book;

记住一点,在aidl中,无论代码是否存在于同一个包中,都需要进行导入。
IBookManager.aidl的逻辑代码如下:

// IBookManager.aidl
package reoger.hut.test2;

import reoger.hut.test2.Book;
import reoger.hut.test2.IOnNewBookArrivedArrivedListener;

interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);

void registerListener(IOnNewBookArrivedArrivedListener listener);
void unRegisterListener(IOnNewBookArrivedArrivedListener listener);
}

然后是IOnNewBookArrivedArrivedListener.aidl的代码,如下:

// IOnNewBookArrivedArrivedListener.aidl
package reoger.hut.test2;

import reoger.hut.test2.Book;

interface IOnNewBookArrivedArrivedListener {
void onNewBookArrived(in Book newBook);
}

接下来是我们服务端的实现,这里我采用的是通过一个service来实现,
BookManagerService.java的代码如下。

public class BookManagerService extends Service {

private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
private RemoteCallbackList<IOnNewBookArrivedArrivedListener> mListeners = new RemoteCallbackList<>();

private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);

private Binder mBinder = new IBookManager.Stub() {

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

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

/**
* 注册监听
* @param listener 监听对象
* @throws RemoteException
*/
@Override
public void registerListener(IOnNewBookArrivedArrivedListener listener) throws RemoteException {
mListeners.register(listener);
Log.d("TAG", "增添监听成功");
}

@Override
public void unRegisterListener(IOnNewBookArrivedArrivedListener listener) throws RemoteException {
mListeners.unregister(listener);
Log.d("TAG", "增添监听成功");
}
};

@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1, "android"));
mBookList.add(new Book(2, "ios"));

new Thread(new ServiceWorker()).start();

}

public BookManagerService() {
}

@Override
public IBinder onBind(Intent intent) {
int check = checkCallingOrSelfPermission("reoger.hut.test2.permission.ACCESS_BOOK_SERVICE");
if(check == PackageManager.PERMISSION_DENIED){
Log.e("TAG","没有对应的权限,无法启动service");
return null;
}
return mBinder;
}

private class ServiceWorker implements Runnable {

@Override
public void run() {
while (!mIsServiceDestoryed.get()) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}

int bookId = mBookList.size() + 1;
Book book = new Book(bookId, "new Book# " + bookId);
onNewBookArrived(book);
}
}
}

private void onNewBookArrived(Book book) {

mBookList.add(book);
final int N = mListeners.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedArrivedListener listener = mListeners.getBroadcastItem(i);
Log.d("TAG", "onNew Book Arrived ,notify listener :");
try {
if (listener != null) {
listener.onNewBookArrived(book);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
mListeners.finishBroadcast();
}
}

在manfiest文件中对service进行申明,并将其设置在一个单独的线程中运行,代码如下:

<service
android:name=".BookManagerService"
android:enabled="true"
android:exported="true"
android:process=":remote">
</service>

最后是我们的客户端代码,如下:

public class MainActivity extends AppCompatActivity {

private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {

switch (msg.what){
case 0x66:
Log.d("TAG","普天同庆 奔走相告"+msg.obj);
break;
default:
super.handleMessage(msg);
}
}
};

private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);

List<Book> list = null;
try {
list = bookManager.getBookList();
for (Book book : list) {
Log.d("TAG",book.toString());
}

Book book = new Book(3,"android 开发艺术探索");
bookManager.addBook(book);
List<Book> list2 = bookManager.getBookList();
for (Book book1 : list2) {
Log.d("TAG","--- "+book1.toString());
}

bookManager.registerListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}

}

@Override
public void onServiceDisconnected(ComponentName name) {

}
};
private IBookManager bookManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,BookManagerService.class);
bindService(intent,connection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onDestroy() {
if(bookManager != null && bookManager.asBinder().isBinderAlive()){
try {
Log.d("TAG","正在停止服务...");
bookManager.unRegisterListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(connection);
super.onDestroy();

}

private IOnNewBookArrivedArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedArrivedListener.Stub(){

@Override
public void onNewBookArrived(Book newBook) throws RemoteException {
mHandler.obtainMessage(0x66,newBook).sendToTarget();
}
};
}

最后运行的结果主要通过打印的日志来显示。

11-12-51.jpg

通过日志信息,可以明确看到我们的服务端和客服端的确进行的数据交换,并且服务端每隔5s发送一个信息给客户端。

关于AIDL,有以下的几点需要特别的注意:

  • AIDL支持基本的数据类型(除short以外的数据类型),也支持String和CharSequence和Parcelable。对于List只支持ArrayList,对于Map只支持HshMap.
  • 如果AIDL文件中用到了自定义的Parcelable对象,必须新建一个和它同名的AIDL文件,并在其中声明它为Parcelable类型。可以参考上面的示例 。
  • AIDL中除了基本的数据类型,其他类型的参数必须标上方向:in,out或者inout,in表示输入型参数,out表示输出型参数,inout表示输入输出型参数。
  • 在AIDL中,只支持方法,不支持声明静态常量。
  • AIDL包结构在服务端和客户端必须保持一致,否运行会出错,这是因为客户端需要反序列化服务端中和AIDL接口相关的所有类。
  • AIDL方法是执行在服务端的Binder线程池中的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,367评论 25 707
  • 一、 什么是IPC? IPC,全称Inter-Process Communication,字面意思就是进程间通信或...
    kuwork阅读 7,939评论 0 8
  • 相关概念 序列化 Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deseria...
    朔野阅读 6,044评论 0 19
  • 唐以丰满为美,瓶花史袁弘道。主要花器盘花,碗花缸花,蓝花,筒花,瓶花,陶剑山,防滑垫,首先学盆花。绘画学园林学色彩...
    萱萱丫头阅读 279评论 0 0
  • 疏格网落鱼相赠,勿尽于食味自更。 莫等禽绝方弃器,应明兽幼且交觥。 居得沃地安十里,净守吾心慕一清。 便让天真归野...
    树先森6阅读 384评论 5 3