ViewPager Fragment中EventBus多次调用问题咨询
兄弟,我太懂你遇到的这个坑了!ViewPager的预加载机制加上Fragment的View生命周期特性,确实会导致每次滑动Fragment时,EventBus跟着反复注册注销,轻则事件接收不稳定,重则可能触发重复注册的异常。下面给你几个靠谱的解决方案:
1. 调整注册/注销的生命周期时机
把EventBus的注册和注销从onCreateView()/onDestroyView()移到Fragment的全局生命周期方法里,比如onAttach()和onDetach(),或者onCreate()和onDestroy()。这些方法只会在Fragment创建和销毁时执行一次,不会因为View的重建(滑动导致)而反复触发:
@Override public void onAttach(Context context) { super.onAttach(context); // 只在Fragment绑定到上下文时注册一次 EventBus.getDefault().register(this); } @Override public void onDetach() { super.onDetach(); // 只在Fragment脱离上下文时注销一次 EventBus.getDefault().unregister(this); }
2. 加标记避免重复注册/注销
如果因为业务需求,必须在View相关的生命周期里处理EventBus,可以给Fragment加一个状态标记,防止重复操作:
private boolean isEventBusRegistered = false; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_movie_pager, container, false); // 只有未注册时才执行注册 if (!isEventBusRegistered) { EventBus.getDefault().register(this); isEventBusRegistered = true; } // 其他View初始化逻辑 return view; } @Override public void onDestroyView() { super.onDestroyView(); // 只有已注册时才执行注销 if (isEventBusRegistered) { EventBus.getDefault().unregister(this); isEventBusRegistered = false; } }
3. 粘性事件适配(按需使用)
如果你的场景是:滑动Fragment后需要接收之前已经发送的MovieBuyEvent,可以考虑使用EventBus的粘性事件。发送事件时使用postSticky(),这样即使Fragment后来注册,也能收到之前的事件:
// 在RecyclerView的ViewHolder点击事件里发送粘性事件 EventBus.getDefault().postSticky(new MovieBuyEvent(/* 携带的数据 */));
然后在Fragment的订阅方法里正常接收即可,粘性事件会保留到被手动移除或者App销毁。
为什么原来的方式会出问题?
ViewPager默认会预加载左右各1个Fragment,当Fragment滑出预加载范围时,系统会销毁它的View(触发onDestroyView()),当再次滑回来时,又会重建View(触发onCreateView())。如果把EventBus的注册注销绑定在这两个方法里,自然会跟着滑动反复执行。
内容的提问来源于stack exchange,提问作者theanilpaudel

