PIC 进程间通信主要有这几种
1.bundle :
简单易用 但是只能传输Bundle支持的对象 常用于四大组件间进程间通信
2.文件共享:
简单易用 但不适合在高并发的情况下 并且读取文件需要时间 不能即时通信 常用于并发程度不高 并且实时性要求不高的情况
3.AIDL :
功能强大 支持一对多并发通信 支持即时通信 但是使用起来比其他的复杂 需要处理好多线程的同步问题 常用于一对多通信 且有RPC 需求的场合(服务端和客户端通信)
4.Messenger :
功能一般 支持一对多串行通信 支持实时通信 但是不能很好处理高并发情况 只能传输Bundle支持的类型 常用于低并发的无RPC需求一对多的场合
5.ContentProvider :
在数据源访问方面功能强大 支持一对多并发操作 可扩展call方法 可以理解为约束版的AIDL 提供CRUD操作和自定义函数 常用于一对多的数据共享场合
6.Socket :
功能强大 可以通过网络传输字节流 支持一对多并发操作 但是实现起来比较麻烦 不支持直接的RPC 常用于网络数据交换
AIDL需要了解的知识,这一篇就够了。
Android:学习AIDL,这一篇文章就够了(上)_lypeer的博客-CSDN博客_aidl
我这里取名为aidl4。
创建一个类,正常的书写其成员变量,建立getter和setter并添加一个无参构造
创建如下类:
public class Book{
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
private String name;
private int price;
public Book() {}
}
按下Alt+Insert,选择Palcelable,可以帮你生成以下代码。
package com.example.aidl4;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
private String name;
private int price;
public Book() {}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeInt(this.price);
}
public void readFromParcel(Parcel source) {
this.name = source.readString();
this.price = source.readInt();
}
protected Book(Parcel in) {
this.name = in.readString();
this.price = in.readInt();
}
//方便打印数据
@Override
public String toString() {
return "name : " + name + " , price : " + price;
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
}
这里要手动添加 toString()。
注意,如果你没有安装Palcelable插件,可以直接在线安装。方法是:
打开File -> Settings -> Pugins -> Browse Repositories 如下,输入 android parcelable code generator :
src目录右击选择new->AIDL,制作两份AIDL文件。
// Book.aidl
//第一类AIDL文件
//这个文件的作用是引入了一个序列化对象 Book 供其他的AIDL文件使用
//注意:Book.aidl与Book.java的包名应当是一样的
package com.example.aidl4;
//注意parcelable是小写
parcelable Book;
// BookManager.aidl
//第二类AIDL文件
//作用是定义方法接口
package com.example.aidl4;
//导入所需要使用的非默认支持数据类型的包
import com.example.aidl4.Book;
interface BookManager {
//所有的返回值前都不需要加任何东西,不管是什么数据类型
List getBooks();
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
void addBook(in Book book);
}
修改 build.gradle 文件:在 android{} 中间加上下面的内容:
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}
点击build->rebuild project ,检查无报错
package com.example.aidl4;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* 服务端的AIDLService.java
*
* Created by lypeer on 2016/7/17.
*/
public class AIDLService extends Service {
public final String TAG = this.getClass().getSimpleName();
//包含Book对象的list
private List mBooks = new ArrayList<>();
//由AIDL文件生成的BookManager
private final BookManager.Stub mBookManager = new BookManager.Stub() {
@Override
public List getBooks() throws RemoteException {
synchronized (this) {
Log.e(TAG, "invoking getBooks() method , now the list is : " + mBooks.toString());
if (mBooks != null) {
return mBooks;
}
return new ArrayList<>();
}
}
@Override
public void addBook(Book book) throws RemoteException {
synchronized (this) {
if (mBooks == null) {
mBooks = new ArrayList<>();
}
if (book == null) {
Log.e(TAG, "Book is null in In");
book = new Book();
}
//尝试修改book的参数,主要是为了观察其到客户端的反馈
book.setPrice(2333);
if (!mBooks.contains(book)) {
mBooks.add(book);
}
//打印mBooks列表,观察客户端传过来的值
Log.e(TAG, "invoking addBooks() method , now the list is : " + mBooks.toString());
}
}
};
@Override
public void onCreate() {
super.onCreate();
Book book = new Book();
book.setName("Android开发艺术探索");
book.setPrice(20220607);
mBooks.add(book);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString()));
return mBookManager;
}
}
修改从
检查确认服务端整体结构是否如下图:
注意,是原封不动的拷贝aidl目录所有内容。
修改MainActivity
package com.example.aidl5;
import androidx.appcompat.app.AppCompatActivity;
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.util.Log;
import android.view.View;
import android.widget.Toast;
import com.example.aidl4.Book;
import com.example.aidl4.BookManager;
import java.util.List;
public class MainActivity extends AppCompatActivity {
//由AIDL文件生成的Java类
private BookManager mBookManager = null;
//标志当前与服务端连接状况的布尔值,false为未连接,true为连接中
private boolean mBound = false;
//包含Book对象的list
private List mBooks;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_aidl);
setContentView(R.layout.activity_main);
if (!mBound) {
attemptToBindService();
Log.w("harry","当前与服务端处于未连接状态,正在尝试重连,请稍后再试");
Toast.makeText(this, "harry 当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show();
return;
}
if (mBookManager == null) return;
Book book = new Book();
book.setName("APP研发录In");
book.setPrice(30);
try {
mBookManager.addBook(book);
Log.e(getLocalClassName(), book.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 按钮的点击事件,点击之后调用服务端的addBookIn方法
*
* @param view
*/
public void addBook(View view) {
//如果与服务端的连接处于未连接状态,则尝试连接
if (!mBound) {
attemptToBindService();
Log.i("harry","no当前与服务端处于未连接状态,正在尝试重连,请稍后再试");
Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show();
return;
}
if (mBookManager == null) return;
Book book = new Book();
book.setName("APP研发录In");
book.setPrice(30);
try {
mBookManager.addBook(book);
Log.e(getLocalClassName(), book.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 尝试与服务端建立连接
*/
private void attemptToBindService() {
Log.i("harry","enter attemptToBindService");
Intent intent = new Intent();
intent.setAction("com.example.aidl4.ALDLService");
intent.setPackage("com.example.aidl4");
Log.i("harry","in attemptToBindService,"+ intent);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStart() {
super.onStart();
if (!mBound) {
attemptToBindService();
}
}
@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mServiceConnection);
mBound = false;
}
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("harry","enter onServiceConnection");
Log.e(getLocalClassName(), "service connected");
mBookManager = BookManager.Stub.asInterface(service);
Log.i("harry","got mBookManager");
mBound = true;
if (mBookManager != null) {
Log.i("harry","mBookManager is not null");
try {
mBooks = mBookManager.getBooks();
Log.i("harry","after getBooks");
Log.e(getLocalClassName(), mBooks.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("harry","enter onServiceDisConnection");
Log.e(getLocalClassName(), "service disconnected");
mBound = false;
}
};
}
在安卓设备上安装两个app,先启动aidl4服务端,再启动aidl5客户端。观察日志:
aidl5客户端:
aidl4服务端
测试成功。
实践出真知,看懂了不如调通了。