场景:
你可能遇到过类似的情况:同一条数据在多个页面上展示,并且这些页面同时存在,在其中某一个页面上修改数据,其他页面能够及时更新。我在工作当中就遇到了一个类似的场景:我们APP内部做了一个论坛,每条帖子都可以被点赞,可以在列表页点赞也可以在详情页点赞。以前只有一个列表页,一个详情页,所以直接通过startActivityForResult和onActivityResult就可以在返回列表页的时候更新列表页的状态。后来又增加了一个列表页,跟前一个列表页有重复数据,上面的那个方法就玩不转了,只得另外在想办法。本文就是从这个问题出发,提出一个解决同类问题的通用方法。
架构:
核心思想:
-
借助EventBus构建一个Publish/Subscribe系统
; - 每个页面就是一个Observer,向EventBus订阅自己感兴趣的事件;
- 当数据对象(Subject)发生改变,发布(Publish)一个事件出来;
- 页面接收到事件更新自己持有的数据、修改页面展示。
实现:
- 事件基类:
public class BaseEvent {
public String uuid;
public BaseEvent(String uuid){
this.uuid = uuid;
}
public BaseEvent(){}
public boolean isMe(String me){
if(TextUtils.isEmpty(uuid)){
return true;
}
return me.equals(uuid);
}
}
- 事件样例:
public class PraiseEvent extends BaseEvent {
public String data;
public PraiseEvent(String uuid,String data){
super(uuid);
this.data = data;
}
}
- 页面处理样例:(这里展示了RecyclerView当中更新数据的做法)
public void onEventMainThread(PraiseEvent event) {
int count = recyclerView.getChildCount()-1;
for(int i=0;i<count;i++){
View child = recyclerView.getChildAt(i);
if(child.getTag() != null){
ItemViewHolder holder = (ItemViewHolder) child.getTag();
if(event.isMe(holder.data.getId())){
Data data = holder.data;
String target = event.data;
if (target.equals(data.getIsLike())) {
return;
}
data.setIsLike(target);
holder.binding.ivLike.setImageResource("Y".equals(data.getIsLike()) ?
R.drawable.ic_like_normal :
R.drawable.ic_like_pressed);
return;
}
}
}
int size = datas.size();
for(int i = 0;i<size;i++){
Data data = datas.get(i);
if(event.isMe(data.getId())){
String target = event.data;
if (target.equals(data.getIsLike())) {
return;
}
data.setIsLike(target);
return;
}
}
}
可能存在的问题:
本方案把所有的subscriber
都注册到了默认的EventBus实例上,可能会影响性能。如果应用模块划分比较明确,可以为每个模块单独分配一个EventBus实例。