Fragment中嵌套Fragment,且被嵌套的Fragment是复用的,点击其中item后进入详情,返回后需要回传数据并刷新列表。
由于是Fragment之间的相互嵌套,不方便使用Intent返回数据,也不方便使用callback回调来返回数据,所以选择了使用EventBus发送消息,但是发现在列表中使用EventBus发送消息后,Fragment中接收消息的方法会执行多次。
发送消息:
EventBus.getDefault().post(new TestEvent());
接收消息:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onTestEvent(TestEvent event) {
onSwipeRefresh();
}
也就是onTestEvent方法会被调用多次,数据也会多次刷新。
原因分析因为Fragment是复用的,而EventBus订阅消息也在复用的Fragment中,导致该消息被多次订阅。以ItemFragment为例。
public class ItemFragment extends Fragment {
private static final String ARG_COLUMN_COUNT = "column-count";
private int mColumnCount = 1;
public ItemFragment() {
}
@SuppressWarnings("unused")
public static ItemFragment newInstance(int columnCount) {
ItemFragment fragment = new ItemFragment();
Bundle args = new Bundle();
args.putInt(ARG_COLUMN_COUNT, columnCount);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
}
@Override
public void onStart() {
super.onStart();
// 订阅消息
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
// 注销订阅
EventBus.getDefault().unregister(this);
}
}
复用ItemFragment:
public class HomeFragment extends Fragment {
private int activeColor = Color.parseColor("#ffffff");
private int normalColor = Color.parseColor("#666666");
private final String[] tabs = new String[]{"第一页", "第二页", "第三页", "第四页", "第五页"};
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
...
vp2.setAdapter(new FragmentStateAdapter(getActivity().getSupportFragmentManager(), getLifecycle()) {
@NonNull
@Override
public Fragment createFragment(int position) {
return ItemFragment.newInstance(position + 10);
}
@Override
public int getItemCount() {
return tabs.length;
}
});
...
}
因为创建了5个ItemFragment对象,所以EventBus被订阅了5次,所以消息时也会被接收5次。
解决方案1、提前在宿主Activity中进行EventBus消息订阅,但是该方法不适合多层级的Fragment嵌套,EventBus订阅不成功,也就接收不到消息。
2、在Fragment中添加标签,识别当前的Fragment。
@Override
public void onStart() {
super.onStart();
// 2 是需要接收消息的Fragment的索引
if(2 == position) {
EventBus.getDefault().register(this);
}
}
@Override
public void onStop() {
super.onStop();
if( 2 == position) {
EventBus.getDefault().unregister(this);
}
}
复用的Fragment中只有索引为2的Fragment才会订阅消息,所以发送消息的时候只有索引为2的Fragment才能接收到消息,也就解决了多次接收消息的问题。
3、消息中添加标记。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onTestEvent(TestEvent event) {
if (event != null) {
// 2 是需要接收消息的Fragment的索引
if(event.getPosition() == 2){
onSwipeRefresh();
}
}
}
EventBus在post消息的时候,把需要哪一个页面刷新的position发送,接收消息时识别根据索引判断需要哪一个页面刷新。不一定要Fragment的position,只要能唯一识别Fragment就行。