Android进程间通信

試著忘記壹切 提交于 2019-12-29 22:44:30

##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时候就去获取另一线程的对象,并对她进行添加

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!