简介
- AIDL概念理解
- AIDL服务端创建
- 客户端创建
- 测试结果
- 测试方法,结果展示
- 自定义接口回调,动态接收服务端消息
- RemoteCallbackList 删除跨进程Listener
一、AIDL概念理解
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数
AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。
其中对于Java编程语言的基本数据类型 (int, long, char, boolean等),String和CharSequence,集合接口类型List和Map,不需要import 语句。 而如果需要在AIDL中使用其他AIDL接口类型,需要import,即使是在相同包结构下。AIDL允许传递实现Parcelable接口的类,需要import.
需要特别注意的是, 对于非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
AIDL只支持接口方法,不能公开static变量。
其中AIDL的方法还提供了oneway这个关键字,可以用关键字oneway来标明远程调用的行为属性,使用了该关键字,那么远程调用将仅仅是调用所需的数据传输过来并立即返回,而不会等待结果的返回,也即是说不会阻塞远程线程的运行。AIDL接口将最终将获得一个从Binder线程池中产生的调用(和普通的远程调用类似)。如果关键字oneway在本地调用中被使用,将不会对函数调用有任何影响。
二、AIDL创建-- 服务端
- 创建Bean 对象 并实现Parcelable 序列化
package mvvm.com.git1;
public class HelloMsg implements Parcelable{
private String msg;
private int pid;
public HelloMsg(Parcel in) {
msg = in.readString();
pid = in.readInt();
}
public HelloMsg(String msg, int pid) {
this.msg = msg;
this.pid = pid;
}
public static final Creator<HelloMsg> CREATOR = new Creator<HelloMsg>() {
@Override
public HelloMsg createFromParcel(Parcel in) {
return new HelloMsg(in);
}
@Override
public HelloMsg[] newArray(int size) {
return new HelloMsg[size];
}
};
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(msg);
dest.writeInt(pid);
}
}
2.AIDL服务端接口创建 ,注意要和Bean对象创建再同一个package 下 。AIDL的特殊要求
创建和HelloMsg Bean同名的 HelloMsg.aidl文件 ,且parcelable 引入 HelloMsg
// HelloMsg.aidl 注意所在的包
package mvvm.com.git1;
//引入bean对象
parcelable HelloMsg;
创建IRemoteService.aidl 所在包 同HelloMsg 一致,且引入 import 引入 HelloMsg 。AIDL的特殊之处
// IRemoteService.aidl 。
package mvvm.com.git1;
import mvvm.com.git1.HelloMsg;
interface IRemoteService {
HelloMsg sayHello();// 服务端 返回 语言
List<HelloMsg> getMsgList(); // 返回 服务端 全部 语言总和
void addMsg(in HelloMsg msg);// 客户端新增的语言
}
3.Rebuild Project 项目 ,会在app -> build -> generated ->source -> aidl -> debug -> 包名 -> IRemoteService 文件 。说明 AIDL创建成功,文件内容后面讲解。
- 创建服务端 RemoteService ,manifest文件中配置 process
/**
* Created by stf on 2020/4/2.
* 服务端
*/
public class RemoteService extends Service {
List<HelloMsg> helloList = new ArrayList<>();
IRemoteService.Stub stub = new IRemoteService.Stub() {
@Override
public HelloMsg sayHello() throws RemoteException {
return new HelloMsg("来自服务端的消息了是1111", 1);
}
@Override
public List<HelloMsg> getMsgList() throws RemoteException {
Log.i("stf", "语言总共" + helloList.size() + "个");
for (int i = 0; i < helloList.size(); i++) {
HelloMsg helloMsg = helloList.get(i);
Log.i("stf", "服务端语言详情--->" + helloMsg.getMsg() + "--->" + helloMsg.getPid());
}
return helloList;
}
@Override
public void addMsg(HelloMsg msg) throws RemoteException {
Log.i("stf", "服务端收到了增加的语言" + msg.getMsg() + "--->" + msg.getPid());
helloList.add(msg);
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;\\绑定bind
}
}
manifest文件中配置 process
<service
android:name=".RemoteService"
android:process="com.stf.remote" />
三、创建客户端
1.客户端负责连接、绑定、解绑 服务端
- 给服务端设置 死亡代理 ,防止 服务端 异常 导致客户端连接失败,导致客户端异常。
- 创建客户端调用 服务端,数据交互
- 连接 服务端
// 客户端向服务端 建立 请求链接
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteService = IRemoteService.Stub.asInterface(service);
Toast.makeText(Main6Activity.this, "onServiceConnected ", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mRemoteService = null;
Toast.makeText(Main6Activity.this, "onServiceDisconnected ", Toast.LENGTH_SHORT).show();
}
};
- 绑定远程服务
Intent intent = new Intent(this, RemoteService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
- 解绑远程服务
// 防止 服务端 连接泄漏 解除绑定
unbindService(mConnection);
- 给远程服务设置死亡代理类
// 当绑定的service异常断开连接后,自动执行此方法
IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mRemoteService == null) {
toastMsg();
return;
}
//解除死亡通知,如果Binder死亡了,不会在触发binderDied方法
mRemoteService.asBinder().unlinkToDeath(deathRecipient, 0);
// 重新绑定一次
Intent intent = new Intent(Main6Activity.this, RemoteService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
};
service.linkToDeath(deathRecipient, 0); // 给远程服务设置死亡代理类
- 测试方法
// 增加语言内容
public void say_add_button(View view) {
if (!isBinderAlive()) {
toastMsg();
return;
}
try {
int i = new Random().nextInt(100);
HelloMsg helloMsg = new HelloMsg("羊皮卷" + i, i);
mRemoteService.addMsg(helloMsg);
mPidText.setText(helloMsg.getMsg() + "-->" + helloMsg.getPid());
} catch (RemoteException e) {
e.printStackTrace();
}
}
// 获取服务端语言内容
public void say_get_button(View view) {
if (!isBinderAlive()) {
toastMsg();
return;
}
try {
List<HelloMsg> helloList = mRemoteService.getMsgList();
Log.i("stf", "服务端返回语言总数为:" + helloList.size());
for (int i = 0; i < helloList.size(); i++) {
HelloMsg helloMsg = helloList.get(i);
Log.i("stf", "客户端收到服务端返回语言详情--->" + helloMsg.getMsg() + "--->" + helloMsg.getPid());
}
mPidText.setText("服务端返回语言总数为:" + helloList.size());
} catch (RemoteException e) {
e.printStackTrace();
}
}
// 每次调用服务端之前 ,判断bind 是否是否存活
public Boolean isBinderAlive() {
return mRemoteService != null && mRemoteService.asBinder().isBinderAlive();
}
四、客户端全部代码
// 客户端
public class Main6Activity extends AppCompatActivity {
private IRemoteService mRemoteService = null;
private TextView mPidText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main6);
mPidText = (TextView) findViewById(R.id.my_pid_text_view);
}
@Override
protected void onStart() {
super.onStart();
// 绑定远程服务
Intent intent = new Intent(this, RemoteService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
// 客户端向服务端 建立 请求链接
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteService = IRemoteService.Stub.asInterface(service);
Toast.makeText(Main6Activity.this, "onServiceConnected ", Toast.LENGTH_SHORT).show();
try {
service.linkToDeath(deathRecipient, 0); // 给远程服务设置死亡代理类
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mRemoteService = null;
Toast.makeText(Main6Activity.this, "onServiceDisconnected ", Toast.LENGTH_SHORT).show();
}
};
// 当绑定的service异常断开连接后,自动执行此方法
IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mRemoteService == null) {
toastMsg();
return;
}
//解除死亡通知,如果Binder死亡了,不会在触发binderDied方法
mRemoteService.asBinder().unlinkToDeath(deathRecipient, 0);
// 重新绑定一次
Intent intent = new Intent(Main6Activity.this, RemoteService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
};
@Override
protected void onStop() {
super.onStop();
// 防止 服务端 链接泄漏 解除绑定
unbindService(mConnection);
}
// 增加语言内容
public void say_add_button(View view) {
if (!isBinderAlive()) {
toastMsg();
return;
}
try {
int i = new Random().nextInt(100);
HelloMsg helloMsg = new HelloMsg("羊皮卷" + i, i);
mRemoteService.addMsg(helloMsg);
mPidText.setText(helloMsg.getMsg() + "-->" + helloMsg.getPid());
} catch (RemoteException e) {
e.printStackTrace();
}
}
// 获取服务端语言内容
public void say_get_button(View view) {
if (!isBinderAlive()) {
toastMsg();
return;
}
try {
List<HelloMsg> helloList = mRemoteService.getMsgList();
Log.i("stf", "服务端返回语言总数为:" + helloList.size());
for (int i = 0; i < helloList.size(); i++) {
HelloMsg helloMsg = helloList.get(i);
Log.i("stf", "客户端收到服务端返回语言详情--->" + helloMsg.getMsg() + "--->" + helloMsg.getPid());
}
mPidText.setText("服务端返回语言总数为:" + helloList.size());
} catch (RemoteException e) {
e.printStackTrace();
}
}
// 每次调用服务端之前 ,判断bind 是否是否存活
public Boolean isBinderAlive() {
return mRemoteService != null && mRemoteService.asBinder().isBinderAlive();
}
public void toastMsg() {
Toast.makeText(this, "服务端异常,请稍后重试", Toast.LENGTH_SHORT).show();
}
}
五、测试结果
- 点击say_add_button 像服务端增加语言内容 。需求:模拟别人给你留言时发消息
log日志如下
- 点击 say_get_button 从服务端获取添加的所有语言 。需求:你自己主动去服务端查询 别人和你的留言内容
log日志如下
到此为止 完成了基本的信息传递。显然上面的交互时留言,貌似没问题,但是 假如 当有新的留言时 ,服务端能不能主动的通知你,上面的交互显然时需要你自己主动查询,并不能满足你的需求。为解决这个问题 ,请继续往下看。
六、自定义接口 动态接收 服务端消息
-
首先创建一个AIDL 接口 ,每个客户端都需要实现这个接口 ,来达到 新留言来的时候通知到它。
因为AIDL 无法创建普通的接口,所以这里创建一个IOnNewMsgArrivedListener.aidl 文件 ,它所在的包还是和前面保持一致
package mvvm.com.git1;
import mvvm.com.git1.HelloMsg;
interface IOnNewMsgArrivedListener {
void OnNewMsgArrived(in HelloMsg msg);//回调方法
}
- 在原来的IRemoteService.aidl 中新增两个接口,注册和解除 接口 。
package mvvm.com.git1;
import mvvm.com.git1.HelloMsg;
import mvvm.com.git1.IOnNewMsgArrivedListener;
interface IRemoteService {
HelloMsg sayHello();// 服务端 返回 语言
List<HelloMsg> getMsgList(); // 返回 服务端 全部 语言总和
void addMsg(in HelloMsg msg);// 客户端新增的语言
void registerListener(IOnNewMsgArrivedListener listener); //注册 新语言来时的事件
void unregisterListener(IOnNewMsgArrivedListener listener); //解除 新语言来时的事件
}
- RemoteService服务端 Sub实现两个新增接口 ,同时开启一个子线程 间隔1s 发送一条留言 并通知 用户。
为了线程安全 ,对前面的服务端RemoteService有点小修改
/**
* Created by stf on 2020/4/2.
* 服务端
*/
public class RemoteService extends Service {
/***
* CopyOnWriteArrayList这是一个ArrayList的线程安全的变体,其原理大概可以通俗的理解为:初始化的时候只有一个容器,
* 很常一段时间,这个容器数据、数量等没有发生变化的时候,
* 大家(多个线程),都是读取(假设这段时间里只发生读取的操作)同一个容器中的数据,所以这样大家读到的数据都是唯一、一致、安全的,
* 但是后来有人往里面增加了一个数据,这个时候CopyOnWriteArrayList 底层实现添加的原理是先copy出一个容器(可以简称副本),
* 再往新的容器里添加这个新的数据,最后把新的容器的引用地址赋值给了之前那个旧的的容器地址,
* 但是在添加这个数据的期间,其他线程如果要去读取数据,仍然是读取到旧的容器里的数据。
*
* 在java.util.concurrent.atomic包下,有AtomicBoolean , AtomicInteger, AtomicLong, AtomicReference等类,
* 它们的基本特性就是在多线程环境下,执行这些类实例包含的方法时,具有排他性,
* 即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,
* 而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入。
*/
private AtomicBoolean mIsServiceDestory = new AtomicBoolean(false); // 控制线程
private CopyOnWriteArrayList<HelloMsg> mHelloList = new CopyOnWriteArrayList<>();
private CopyOnWriteArrayList<IOnNewMsgArrivedListener> msgArrivedListeners = new CopyOnWriteArrayList<>();
IRemoteService.Stub stub = new IRemoteService.Stub() {
@Override
public HelloMsg sayHello() throws RemoteException {
return new HelloMsg("来自服务端的消息了是1111", 1);
}
@Override
public List<HelloMsg> getMsgList() throws RemoteException {
Log.i("stf", "语言总共" + mHelloList.size() + "个");
for (int i = 0; i < mHelloList.size(); i++) {
HelloMsg helloMsg = mHelloList.get(i);
Log.i("stf", "服务端语言详情--->" + helloMsg.getMsg() + "--->" + helloMsg.getPid());
}
return mHelloList;
}
@Override
public void addMsg(HelloMsg msg) throws RemoteException {
Log.i("stf", "服务端收到了增加的语言" + msg.getMsg() + "--->" + msg.getPid());
mHelloList.add(msg);
}
@Override
public void registerListener(IOnNewMsgArrivedListener listener) throws RemoteException {
if (!msgArrivedListeners.contains(listener)) {
msgArrivedListeners.add(listener);
} else {
Log.i("stf", "registerListener: already exists ");
}
Log.i("stf", "registerListener: size" + msgArrivedListeners.size());
}
@Override
public void unregisterListener(IOnNewMsgArrivedListener listener) throws RemoteException {
if (!msgArrivedListeners.contains(listener)) {
msgArrivedListeners.remove(listener);
} else {
Log.i("stf", "unregisterListener: already exists ");
}
Log.i("stf", "unregisterListener: size" + msgArrivedListeners.size());
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
@Override
public void onDestroy() {
super.onDestroy();
mIsServiceDestory.set(true);
}
@Override
public void onCreate() {
super.onCreate();
//开启子线程 创建新留言
new Thread(new ServiceWorker()).start();
}
private class ServiceWorker implements Runnable {
@Override
public void run() {
while (!mIsServiceDestory.get()) {
try {
Thread.sleep(1000);
int helloId = mHelloList.size() + 1;
HelloMsg helloMsg = new HelloMsg("我来了,大哥" + helloId, helloId);
if (helloId == 10) {
mIsServiceDestory.set(true);
}
Log.i("stf", "服务端有新留言了: " + helloMsg.getMsg());
onMsgArrived(helloMsg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//通知用户 新留言来了
private void onMsgArrived(HelloMsg helloMsg) {
mHelloList.add(helloMsg); //收集所有留言
// Log.i("stf", "onMsgArrived: noitfy listenters:" + msgArrivedListeners.size());
for (int i = 0; i < msgArrivedListeners.size(); i++) {
IOnNewMsgArrivedListener listener = msgArrivedListeners.get(i);
try {
listener.OnNewMsgArrived(helloMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
- 客户端负责 注册 及 解绑 当有新留言来时的回调事件;
Handler 切换到UI 线程 更新 页面 信息
// 客户端
public class Main6Activity extends AppCompatActivity {
private IRemoteService mRemoteService = null;
private TextView mPidText;
private MyHandler myHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main6);
mPidText = (TextView) findViewById(R.id.my_pid_text_view);
myHandler = new MyHandler(this);
}
@Override
protected void onStart() {
super.onStart();
// 绑定远程服务
Intent intent = new Intent(this, RemoteService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
// 客户端向服务端 建立 请求链接
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteService = IRemoteService.Stub.asInterface(service);
Toast.makeText(Main6Activity.this, "onServiceConnected ", Toast.LENGTH_SHORT).show();
try {
service.linkToDeath(deathRecipient, 0); // 给远程服务设置死亡代理类
mRemoteService.registerListener(msgArrivedListener);// 注册服务端有语言时 更新事件
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mRemoteService = null;
Toast.makeText(Main6Activity.this, "onServiceDisconnected ", Toast.LENGTH_SHORT).show();
}
};
// 当绑定的service异常断开连接后,自动执行此方法
IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mRemoteService == null) {
toastMsg();
return;
}
//解除死亡通知,如果Binder死亡了,不会在触发binderDied方法
mRemoteService.asBinder().unlinkToDeath(deathRecipient, 0);
// 重新绑定一次
Intent intent = new Intent(Main6Activity.this, RemoteService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
};
//创建 新语言来时的监听
private IOnNewMsgArrivedListener msgArrivedListener = new IOnNewMsgArrivedListener.Stub() {
@Override
public void OnNewMsgArrived(HelloMsg msg) throws RemoteException {
Message message = myHandler.obtainMessage(1, msg);
message.obj = msg.getMsg();
message.arg1 = msg.getPid();
message.sendToTarget();
}
};
// 创建静态的Handler 防止内存泄漏
static class MyHandler extends Handler {
WeakReference<Main6Activity> outerClass;
MyHandler(Main6Activity activity) {
outerClass = new WeakReference<Main6Activity>(activity);
}
@Override
public void handleMessage(android.os.Message msg) {
Main6Activity main6Activity = outerClass.get();
switch (msg.what) {
case 1: {
//使用theClass访问外部类成员和方法
Log.i("stf", "客户端收到了服务的新留言 :" + msg.obj + "-->" + msg.arg1);
break;
}
default: {
Log.w("stf", "未知的Handler Message:" + msg.what);
super.handleMessage(msg);
}
}
}
}
@Override
protected void onStop() {
super.onStop();
if (!isBinderAlive()) {
return;
}
try {
Log.i("stf", "unregister lisenter :" + msgArrivedListener);
mRemoteService.unregisterListener(msgArrivedListener);
// 防止 服务端 链接泄漏 解除绑定
unbindService(mConnection);
} catch (Exception e) {
e.printStackTrace();
}
}
// 增加语言内容
public void say_add_button(View view) {
if (!isBinderAlive()) {
toastMsg();
return;
}
try {
int i = new Random().nextInt(100);
HelloMsg helloMsg = new HelloMsg("羊皮卷" + i, i);
mRemoteService.addMsg(helloMsg);
mPidText.setText(helloMsg.getMsg() + "-->" + helloMsg.getPid());
} catch (RemoteException e) {
e.printStackTrace();
}
}
// 获取服务端语言内容
public void say_get_button(View view) {
if (!isBinderAlive()) {
toastMsg();
return;
}
try {
List<HelloMsg> helloList = mRemoteService.getMsgList();
Log.i("stf", "服务端返回语言总数为:" + helloList.size());
for (int i = 0; i < helloList.size(); i++) {
HelloMsg helloMsg = helloList.get(i);
Log.i("stf", "客户端收到服务端返回语言详情--->" + helloMsg.getMsg() + "--->" + helloMsg.getPid());
}
mPidText.setText("服务端返回语言总数为:" + helloList.size());
} catch (RemoteException e) {
e.printStackTrace();
}
}
// 每次调用服务端之前 ,判断bind 是否是否存活
public Boolean isBinderAlive() {
return mRemoteService != null && mRemoteService.asBinder().isBinderAlive();
}
public void toastMsg() {
Toast.makeText(this, "服务端异常,请稍后重试", Toast.LENGTH_SHORT).show();
}
}
- 测试
启动服务端,每间隔1s 向注册 回调事件的用户发送一条留言
log 如下图
七、RemoteCallBackList 删除跨进 listener
到这里你感觉AIDL已经结束了,很简单嘛。那你像的太简单了
从上面的代码看出 ,Main6Activity 的onStop方法 去解除 已经注册到服务端的listner ,这就相当于用户不用 接收新留言了。如果按back 键退出Main6Activity ,打印出的logo 如下
程序没像我们预期的那样去执行,在解除的过程中,服务端竟然无法找到之前注册的哪个listener。在客户端我们注册和解除的时候明明时同一个,但是结果显示 却不是一个。
其实这是必然的,上面的写法在我们平时开始时对的,因为那是在同一个进程中,但是在多进程中却无法生效,因为Binder会把客户端传来的对象重新转化为一个新的对象。客户端虽然时同一个listener 但是到了服务端就发生了变化,对象是不能夸进程传输的 ,这就是AIDL 中自定义对象都必须实现Parcelable 接口的原因。那么此问题怎么破呢?
办法来了
使用RemoteCallBackList ,系统专门提供的删除跨进程listener接口。它的原理很简单,内部有一个Map 来保存AIDL回调。
当客户端解除注册的时候,只要遍历服务端所有的listener ,找到客户端相同的listener 具有相同的Binder对象,删掉即可。它还有其他功能,内部自动实现了线程同步,所以在注册和解除的时候不需要手动做任何同步工作。
对服务端做以下修改
RemoteCallbackList 替换 CopyOnWriteArrayList 、registerListener 和unregisterListener 回调 修改、onMsgArrived 方法修改
最终服务端代码如下
/**
* Created by stf on 2020/4/2.
* 服务端
*/
public class RemoteService extends Service {
/***
* CopyOnWriteArrayList这是一个ArrayList的线程安全的变体,其原理大概可以通俗的理解为:初始化的时候只有一个容器,
* 很常一段时间,这个容器数据、数量等没有发生变化的时候,
* 大家(多个线程),都是读取(假设这段时间里只发生读取的操作)同一个容器中的数据,所以这样大家读到的数据都是唯一、一致、安全的,
* 但是后来有人往里面增加了一个数据,这个时候CopyOnWriteArrayList 底层实现添加的原理是先copy出一个容器(可以简称副本),
* 再往新的容器里添加这个新的数据,最后把新的容器的引用地址赋值给了之前那个旧的的容器地址,
* 但是在添加这个数据的期间,其他线程如果要去读取数据,仍然是读取到旧的容器里的数据。
*
* 在java.util.concurrent.atomic包下,有AtomicBoolean , AtomicInteger, AtomicLong, AtomicReference等类,
* 它们的基本特性就是在多线程环境下,执行这些类实例包含的方法时,具有排他性,
* 即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,
* 而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入。
*/
private AtomicBoolean mIsServiceDestory = new AtomicBoolean(false); // 控制线程
private CopyOnWriteArrayList<HelloMsg> mHelloList = new CopyOnWriteArrayList<>();
private RemoteCallbackList<IOnNewMsgArrivedListener> msgArrivedListeners = new RemoteCallbackList<>();
IRemoteService.Stub stub = new IRemoteService.Stub() {
@Override
public HelloMsg sayHello() throws RemoteException {
return new HelloMsg("来自服务端的消息了是1111", 1);
}
@Override
public List<HelloMsg> getMsgList() throws RemoteException {
Log.i("stf", "语言总共" + mHelloList.size() + "个");
for (int i = 0; i < mHelloList.size(); i++) {
HelloMsg helloMsg = mHelloList.get(i);
Log.i("stf", "服务端语言详情--->" + helloMsg.getMsg() + "--->" + helloMsg.getPid());
}
return mHelloList;
}
@Override
public void addMsg(HelloMsg msg) throws RemoteException {
Log.i("stf", "服务端收到了增加的语言" + msg.getMsg() + "--->" + msg.getPid());
mHelloList.add(msg);
}
@Override
public void registerListener(IOnNewMsgArrivedListener listener) throws RemoteException {
msgArrivedListeners.register(listener);
// 下面两行仅仅是为了统计注册事件个数写的,后期可以删除掉
Log.i("stf","-registerListener size-->"+msgArrivedListeners.beginBroadcast());
msgArrivedListeners.finishBroadcast();
}
@Override
public void unregisterListener(IOnNewMsgArrivedListener listener) throws RemoteException {
msgArrivedListeners.unregister(listener);
// 下面两行仅仅是为了统计注册事件个数写的,后期可以删除掉
Log.i("stf","-unregisterListener size-->"+msgArrivedListeners.beginBroadcast());
msgArrivedListeners.finishBroadcast();
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
@Override
public void onDestroy() {
super.onDestroy();
mIsServiceDestory.set(true);
}
@Override
public void onCreate() {
super.onCreate();
//开启子线程 创建新留言
new Thread(new ServiceWorker()).start();
}
private class ServiceWorker implements Runnable {
@Override
public void run() {
while (!mIsServiceDestory.get()) {
try {
Thread.sleep(1000);
int helloId = mHelloList.size() + 1;
HelloMsg helloMsg = new HelloMsg("我来了,大哥" + helloId, helloId);
if (helloId == 10) {
mIsServiceDestory.set(true);
}
Log.i("stf", "服务端有新留言了:" + helloMsg.getMsg());
onMsgArrived(helloMsg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//通知用户 新留言来了
private void onMsgArrived(HelloMsg helloMsg) {
mHelloList.add(helloMsg); //收集所有留言
final int i = msgArrivedListeners.beginBroadcast(); // 和finishBroadcast 配对使用
for (int j = 0; j < i; j++) {
IOnNewMsgArrivedListener broadcastItem = msgArrivedListeners.getBroadcastItem(j);
if (broadcastItem != null) {
try {
broadcastItem.OnNewMsgArrived(helloMsg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
msgArrivedListeners.finishBroadcast();
}
}
-
验证结果 Main6Activity 10条留言执行完之后 ,按Back 键 ,log如下