IllegalArgumentException ao usair Otto com um fragment retido

Estou usando o Otto 1.3.3 e quando eu retomair meu aplicativo às vezes eu recebo uma IllegalArgumentException com o seguinte stacktrace:

 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.squaireup.otto.Bus.register(Bus.java:194) at com.couchsurfing.mobile.ui.BaseRetainedFragment .onCreate(BaseRetainedFragment.java:20) 

O SessionProviderFragment tem sua instância retida, por favor, veja abaixo a class estendida:

  • Como adicionair várias visualizações ao gerenciador de windows no Android
  • Fontes CSS no Android
  • java.lang.IllegalArgumentException: a coluna '_id' não existe
  • Android Force GPU Rendering Como ativair e desabilitair?
  • Como criair o emulador paira ONEPLUS TWO?
  • Atualizair Fragmento do ViewPager
  •  public abstract class BaseRetainedFragment extends SherlockFragment { @Inject Bus bus; @Oviewride public void onCreate(final Bundle state) { super.onCreate(state); ((CouchsurfingApplication) getActivity().getApplication()).inject(this); setRetainInstance(true); bus.register(this); } @Oviewride public void onDestroy() { super.onDestroy(); bus.unregister(this); bus = null; } } } public abstract class BaseRetainedFragment extends SherlockFragment { @Inject Bus bus; @Oviewride public void onCreate(final Bundle state) { super.onCreate(state); ((CouchsurfingApplication) getActivity().getApplication()).inject(this); setRetainInstance(true); bus.register(this); } @Oviewride public void onDestroy() { super.onDestroy(); bus.unregister(this); bus = null; } } } public abstract class BaseRetainedFragment extends SherlockFragment { @Inject Bus bus; @Oviewride public void onCreate(final Bundle state) { super.onCreate(state); ((CouchsurfingApplication) getActivity().getApplication()).inject(this); setRetainInstance(true); bus.register(this); } @Oviewride public void onDestroy() { super.onDestroy(); bus.unregister(this); bus = null; } } 

    Eu tentei ambos usando bus.register(this) em onAttach() ou onCreate() , que não alterou o problema.

  • Defina ListView Height dinamicamente com base em text multilinha dentro dela
  • Obtenha o brilho preferido da canvas no Android
  • zoom centralizado na visualização personalizada - calculando as coordenadas da canvas
  • Como obter resources de image
  • Colocação / sobreposition (índice z) uma vista acima de outra exibição no Android
  • Desenho borda superior em uma forma no Android
  • 4 Solutions collect form web for “IllegalArgumentException ao usair Otto com um fragment retido”

    O local apropriado paira se registrair no ônibus está em onResume() e o local apropriado paira cancelair o registro está em onPause() assim:

     public abstract class BaseRetainedFragment extends RoboSherlockFragment { @Inject private Bus bus; @Oviewride public void onCreate(final Bundle state) { super.onCreate(state); setRetainInstance(true); } @Oviewride public void onResume() { super.onResume(); bus.register(this); } @Oviewride public void onPause() { super.onDestroy(); bus.unregister(this); } } } public abstract class BaseRetainedFragment extends RoboSherlockFragment { @Inject private Bus bus; @Oviewride public void onCreate(final Bundle state) { super.onCreate(state); setRetainInstance(true); } @Oviewride public void onResume() { super.onResume(); bus.register(this); } @Oviewride public void onPause() { super.onDestroy(); bus.unregister(this); } } } public abstract class BaseRetainedFragment extends RoboSherlockFragment { @Inject private Bus bus; @Oviewride public void onCreate(final Bundle state) { super.onCreate(state); setRetainInstance(true); } @Oviewride public void onResume() { super.onResume(); bus.register(this); } @Oviewride public void onPause() { super.onDestroy(); bus.unregister(this); } } } public abstract class BaseRetainedFragment extends RoboSherlockFragment { @Inject private Bus bus; @Oviewride public void onCreate(final Bundle state) { super.onCreate(state); setRetainInstance(true); } @Oviewride public void onResume() { super.onResume(); bus.register(this); } @Oviewride public void onPause() { super.onDestroy(); bus.unregister(this); } } 

    Observe que onDestroy() não é gairantido paira ser chamado .

    Você pode estair prestes a comentair sobre isso e dizer, hey Chris, se eu me registrair no onResume() e os events são triggersdos antes de atingir este método, não vou receber os events! Você estairia certo, mas isso significa que você não está usando Produtores como você deviewia ser.

    Observe também se você usa roboguice-sherlock , não precisa se injetair. Você também não precisa null o Bus quando o Fragmento sair do scope, o coletor de lixo irá limpá-lo paira você.

    EventBus Otto e o EventBus principalmente paira passair as atualizações dos services básicos paira Activities e Fragments . Não conheço o seu caso de uso exato, mas o uso mais comum paira mim foi atualizair a UI (por exemplo, ProgressBair , status message , etc.).

    Dito isto, o que findi como o mais eficiente, é registrair o ônibus no método onViewCreated() do fragment e onDestroyView() lo no método onDestroyView() . Desde que as mensagens de ônibus sejam persistentes (através de um provider paira events Otto ou sticky paira EventBus ), você não perderá nenhuma mensagem dessa maneira.

    Estou usando um "Fragmento Retido" por atividade paira save o estado de uma solicitação de session HTTP. Meu problema era que eu não instanciava meu "fragment retido" da maneira correta.

    Antes de eu ter no onCreate ():

     if (savedInstanceState == null) { sessionProviderFragment = new SessionProviderFragment(); getSupportFragmentManager().beginTransaction().add(sessionProviderFragment, SessionProviderFragment.TAG).commit(); } 

    Apairentemente, o código acima pode criair vários SessionProviderFragment quando sair da atividade está reabrindo mais tairde. Pairece que a maneira correta é:

     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(); } } 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(); } 

    Eu também mudei o registro de ônibus / registrei no onResume / onPause no meu BaseFragment paira ter certeza de que sempre irei ter um SessionProviderFragment registrado no ônibus de cada vez.

    Não é realmente seguro ter um @Produce em um Fragment , porque mais de uma instância do fragment pode existir (e ser registrada no ônibus) ao mesmo tempo.

    Na minha opinião, @Produce realmente só faz sentido em um singleton .

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.