##Android 进程间通信
在Android开发中线程是CPU调度的最小单元,进程是指一个执行单元,一个进程最少包括一个线程,也就是UI线程。当然也可以有多个线程
因为每个进程都会分配一个虚拟机,而每个虚拟机都对应着不同的内训单元,所以一些传统的通信方式就失去了效果,比如我们定义了一个静态变量a = 0,在A进程赋值a = 1,在b线程中查看还是为0.所以进程间通讯才区别于不同于畅通方式,成为一套体系。
为什么使用多进程?
1、单进程所分配的内存不够,需要更多的内存。在早期android系统只为一个单进程的应用分配了16M的可用内存,随着手机的硬件的提升和android系统的改进,虽然可分配内存越来越多,但仍旧可以通过开启多进程来获取更多的内存来处理自己App的业务
2、独立运行的组件,比如个推,它的服务会另开一个进程。
3进行一些“不可告人”的操作的处理,比如双守护进程,来尽力使自己的应用不被系统杀死,或者获取用户的个人信息等其他信息。
进程间通信所要涉及知识点总结:
1序列化
2Binder
3多种进程通信的详细使用方式
4通信方式的选择
第一部分:序列化
进程间通信需要对传输的对象进行序列化的操作,当然像基础类型还有String为例外List ,MapMessage 等都是已经实现了序列化接口。
(1)implements Serializable
java提供的接口,只需要继承即可,注意serialversionUID:用来判断对象的属性等是否发生了变化,如若不指定,在类的属性发生变化时候,系统会自动变化serialversionUID的值,这时可能会导致发序列化失败,如入指定则可以避免这种情况,但是当变量的type发生变化时候仍然会序列化失败 ,比如从int ---->String
(2)extends Parcelable
Android特有的序列化工具,主要在内存序列化上有高性能的表现,推荐此种
第二部分:BInder 的理解在这里插入代码片
/*
- This file is auto-generated. DO NOT MODIFY.
- Original file: C:\Users\zdmin\AndroidStudioProjects\aidpipc\app\src\main\aidl\com\coder\aidpipc\server\BookManager.aidl
/
package com.coder.aidpipc.server;
public interface BookManager extends android.os.IInterface
{
/* Local-side IPC implementation stub class. /
public static abstract class Stub extends android.os.Binder implements com.coder.aidpipc.server.BookManager
{
private static final java.lang.String DESCRIPTOR = “com.coder.aidpipc.server.BookManager”;
/* Construct the stub at attach it to the interface. /
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/* - Cast an IBinder object into an com.coder.aidpipc.server.BookManager interface,
- generating a proxy if needed.
*/
public static com.coder.aidpipc.server.BookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.coder.aidpipc.server.BookManager))) {
return ((com.coder.aidpipc.server.BookManager)iin);
}
return new com.coder.aidpipc.server.BookManager.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
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(descriptor);
java.util.List<com.coder.aidpipc.server.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBookInOut:
{
data.enforceInterface(descriptor);
com.coder.aidpipc.server.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.coder.aidpipc.server.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBookInOut(_arg0);
reply.writeNoException();
if ((_arg0!=null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.coder.aidpipc.server.BookManager
{
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;
}
@Override public java.util.List<com.coder.aidpipc.server.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.coder.aidpipc.server.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.coder.aidpipc.server.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBookInOut(com.coder.aidpipc.server.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_addBookInOut, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
book.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBookInOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.coder.aidpipc.server.Book> getBookList() throws android.os.RemoteException;
public void addBookInOut(com.coder.aidpipc.server.Book book) throws android.os.RemoteException;
}
上方为sdk生成代码,分析AddBook方法:
1、当客户端远程调用方法是时候。客户端的当前线程会被挂起,所以当发方法比较耗时时候,不宜在UI线程发起调用
2、BInder方法运行在BInder 的线程池中,所以不管BInder中方法的实现耗不耗时,都不应该在创建新的线程。
调用过程如下
binder是运行在服务端的,我们可以对binder出第一个代理,当binder死亡时能回调给client ,
service.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
//可以进行重连等操作
}
}, 0);
进程间通讯方式
1文件系统(不做解释)
2bundle(intent)(不做解释)
3sharePreference(不做解释)
4messenger
5aidl
方式4:利用messenger进行进程间通信
实现:客户端发消息给服务端,服务端收到消息后返回给客户端
先看下 Messenger的l两个构造方法
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
//可看出底层的实现为aidl
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
上代码
服务端
package com.coder.ipc;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
//进程通信的服务端
public class MyMessageService extends Service {
public static Messenger messenger = new Messenger(new ServiceHandle());
public static class ServiceHandle extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Contract.CLIENT_SEND_TYPE:
Log.e(Contract.LOG_TAG, msg.getData().getString(Contract.MESSAGE_CONTENT));
Messenger reMessage = msg.replyTo;
Message message = Message.obtain(null ,Contract.SERVICE_SEND_TYPE);
Bundle data = new Bundle();
data.putString(Contract.MESSAGE_CONTENT, "来自服务端的消息");
message.setData(data);
try {
reMessage.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
客户端
package com.coder.ipc;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
ServiceConnection serviceConnection;
Messenger messenger;
public static class ClientHandle extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Contract.SERVICE_SEND_TYPE:
Log.e(Contract.LOG_TAG, msg.getData().getString(Contract.MESSAGE_CONTENT));
break;
default:
super.handleMessage(msg);
}
}
}
Messenger mreMessage = new Messenger(new ClientHandle());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initVa();
Intent intent = new Intent(this, MyMessageService.class);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
public void initVa() {
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
Message message = Message.obtain(null ,Contract.CLIENT_SEND_TYPE);
//此处切记把要处理服务端返回消息的
//messenger传递给服务端
message.replyTo = mreMessage;
Bundle data = new Bundle();
data.putString(Contract.MESSAGE_CONTENT, “来自客户端消息”);
message.setData(data);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
@Override
public void unbindService(ServiceConnection conn) {
unbindService(serviceConnection);
super.unbindService(conn);
}
}
控制类
package com.coder.ipc;
public class Contract {
public static final String LOG_TAG = “message”;
public static final String MESSAGE_CONTENT = “message_content”;
public static final int SERVICE_SEND_TYPE = 1;
public static final int CLIENT_SEND_TYPE = 2;
}
方式5:aidl方式实现进程间通信
AIDL交界口定义语言但并不是语言,二十Android系统实现的一种快速实现进程间通讯的快捷方式,内部通过对binder的控制来进行实现,所以在代码编写上要符合Android给出规则,系统会帮助实现功能代码的以下规则
实现统一应用不同进程间通信,可看做有相同shareId的不同应用
AIDL文件以 .aidl 为后缀名
AIDL支持的数据类型分为如下几种:
八种基本数据类型:byte、char、short、int、long、float、double、boolean
String,CharSequence
实现了Parcelable接口的数据类型
List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值
定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。定向Tag具体的使用差别后边会有介绍
明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下
1:创建书籍类,并创建同名aidl文件,创建挨打了文件时,系统会默认创建bookmanagr内定义了提供给客户端调用的方法
来实现通信
package com.coder.aidpipc.server;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return “book name:” + name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
}
public void readFromParcel(Parcel dest) {
name = dest.readString();
}
protected Book(Parcel in) {
this.name = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
}
Book.aidl:
// Book.aidl
package com.coder.aidpipc.server;
// Declare any non-default types here with import statements
parcelable Book;对要传输的类型进行声明
BookMananager:
// BookManager.aidl
package com.coder.aidpipc.server;
// Declare any non-default types here with import statements
import com.coder.aidpipc.server.Book;
interface BookManager {
List getBookList();
void addBookInOut(inout Book book);
}
服务代码:
package com.coder.aidpipc.server;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
public class AidlService extends Service {
List bookList = new ArrayList<>();
public void initData() {
bookList.add(new Book(“钢铁是怎样练成的”));
}
private final BookManager.Stub stub = new BookManager.Stub() {
@Override
public List getBookList() throws RemoteException {
return bookList;
}
@Override
public void addBookInOut(Book book) throws RemoteException {
bookList.add(book);
}
};
@Override
public void onCreate() {
super.onCreate();
initData();
}
@Override
public IBinder onBind(Intent intent) {
return stub;
}
}
声明:
<service android:name=".server.AidlService"
android:process=":remote"></service>
用户端:
package com.coder.aidpipc.client;
import android.content.ComponentName;
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 com.coder.aidpipc.R;
import com.coder.aidpipc.server.AidlService;
import com.coder.aidpipc.server.Book;
import com.coder.aidpipc.server.BookManager;
import java.util.List;
public class MainActivity extends AppCompatActivity {
ServiceConnection connection;
BookManager bookManager;
List bookList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initConnect();
Intent intent = new Intent(this, AidlService.class);
bindService(intent,connection,BIND_AUTO_CREATE);
}
public void initConnect() {
connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = BookManager.Stub.asInterface(service);
try {
bookList = bookManager.getBookList();
bookManager.addBookInOut(new Book(“第一本书”));
bookList = bookManager.getBookList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
}
打开activity时候就去获取另一线程的对象,并对她进行添加
来源:CSDN
作者:W_Xcode
链接:https://blog.csdn.net/W_Xcode/article/details/103694167