我正在使用Otto 1.3.3,当我恢复申请时,有时会得到IllegalArgumentException
以下的堆栈跟踪:
Caused by: java.lang.IllegalArgumentException: Producer method for type class
com.couchsurfing.mobile.ui.setup
.SessionProviderFragment$SessionConnectionStateChangeEvent found on
type class com.couchsurfing.mobile.ui.setup.SessionProviderFragment,
but already registered by type class
com.couchsurfing.mobile.ui.setup.SessionProviderFragment.
at com.squareup.otto.Bus.register(Bus.java:194)
at com.couchsurfing.mobile.ui.BaseRetainedFragment
.onCreate(BaseRetainedFragment.java:20)
SessionProviderFragment
保留了其实例,请在扩展类下面找到:
public abstract class BaseRetainedFragment extends SherlockFragment {
@Inject
Bus bus;
@Override
public void onCreate(final Bundle state) {
super.onCreate(state);
((CouchsurfingApplication) getActivity().getApplication()).inject(this);
setRetainInstance(true);
bus.register(this);
}
@Override
public void onDestroy() {
super.onDestroy();
bus.unregister(this);
bus = null;
}
}
我尝试使用bus.register(this)
或onAttach()
中的onCreate()
,但未改变此问题。
答案 0 :(得分:7)
在公交车上注册的正确位置在onResume()
,取消注册的正确位置在onPause()
中,如下所示:
public abstract class BaseRetainedFragment extends RoboSherlockFragment {
@Inject private Bus bus;
@Override
public void onCreate(final Bundle state) {
super.onCreate(state);
setRetainInstance(true);
}
@Override
public void onResume() {
super.onResume();
bus.register(this);
}
@Override
public void onPause() {
super.onDestroy();
bus.unregister(this);
}
}
请注意,onDestroy()
为not guaranteed to be called。
你可能会对此发表评论,然后说,嘿Chris,如果我在onResume()
注册并且事件在我点击此方法之前被解雇我将不会收到这些事件!你是对的,但这意味着你没有像你应该那样使用Producers。
另请注意,如果您使用roboguice-sherlock,则无需自己注射。当Fragment超出范围时,您也不需要null
Bus
垃圾收集器将为您清理它。
答案 1 :(得分:1)
我主要使用Otto
和EventBus
将更新从后台服务传递到Activities
和Fragments
。我不知道您的确切用例,但最常见的用途是更新用户界面(例如ProgressBar
,status message
等)。
尽管如此,我发现最有效的方法是在片段的onViewCreated()
方法中注册总线,并在onDestroyView()
方法中取消注册。如果总线消息是持久性的(通过provider
用于Otto或sticky
EventBus
事件,则不会以任何方式丢失任何消息。
答案 2 :(得分:1)
我在每个活动中使用一个“保留片段”来保存HTTP会话请求的状态。我的问题是我没有以正确的方式实例化我的“保留碎片”。
在进入onCreate()之前:
if (savedInstanceState == null) {
sessionProviderFragment = new SessionProviderFragment();
getSupportFragmentManager().beginTransaction().add(sessionProviderFragment,
SessionProviderFragment.TAG).commit();
}
显然,当退出活动后再重新打开时,上面的代码可能会创建多个SessionProviderFragment
。
它接缝的正确方法是:
sessionProviderFragment = (SessionProviderFragment) getSupportFragmentManager()
.findFragmentByTag(SessionProviderFragment.TAG);
// If not retained (or first time running), we need to create it.
if (sessionProviderFragment == null) {
sessionProviderFragment = new SessionProviderFragment();
getSupportFragmentManager().beginTransaction().add(sessionProviderFragment,
SessionProviderFragment.TAG).commit();
}
if (savedInstanceState == null) {
initUiFragment();
}
我还在我的BaseFragment中的onResume / onPause中移动了总线注册/取消注册,以确保我一次总是在总线上注册一个SessionProviderFragment
。
答案 3 :(得分:0)
在@Produce
上设置Fragment
并不是真的安全,因为片段的多个实例可以存在(并在总线上注册)同一时间。
在我看来@Produce
实际上只对singleton
有意义。