7

我正在使用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)inonAttach()onCreate(),但这并没有改变问题。

4

4 回答 4

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()保证会被调用

您可能会对此发表评论并说,嘿,克里斯,如果我在使用onResume()此方法之前注册并触发了事件,我将不会收到事件!你是对的,但这意味着你没有像你应该使用的那样使用生产者。

另请注意,如果您使用roboguice-sherlock,您不必自己注射。您也不需要nullBusFragment 超出范围时,垃圾收集器会为您清理它。

于 2013-10-11T22:16:02.847 回答
1

我已经使用Otto并且EventBus主要将更新从后台服务传递到ActivitiesFragments. 我不知道您的确切用例,但对我来说最常见的用途是更新 UI(例如ProgressBarstatus message等)。

话虽如此,我发现最有效的是onViewCreated()在片段的方法中注册总线并在方法中取消注册onDestroyView()。假设总线消息是持久的(通过providerOtto 的 a 或的sticky事件EventBus),您不会以这种方式丢失任何消息。

于 2013-05-15T08:25:32.003 回答
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在总线上注册一个。

于 2013-05-18T01:23:05.067 回答
0

@Produce使用on a并不是很安全Fragment,因为可以同时存在多个片段实例(并在总线上注册)。

在我看来@Produce,真的只对singleton.

于 2013-05-17T05:48:59.823 回答