2012-06-12 9 views
7

Oto prosty android app został utworzony w celu wykazania mój problem:android onCreateOptionsMenu zwane dwukrotnie podczas przywracania stanu

public class OptionMenuTest extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.d("test", "create activity"); 
     setContentView(R.layout.options_layout); 
     if(getFragmentManager().findFragmentByTag("frag") == null) { 
      getFragmentManager().beginTransaction().add(R.id.option_fragment_container, new OptionMenuFragment(), "frag").commit(); 
     } 

    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     Log.d("test", "saving Activity state"); 
     super.onSaveInstanceState(outState); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     Log.d("test", "create Activity options menu"); 
     menu.add("activity"); 
     return true; 
    } 
} 

Fragment:

public class OptionMenuFragment extends Fragment { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.d("test", "create fragment"); 
     setHasOptionsMenu(true); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     TextView tv = new TextView(getActivity()); 
     tv.setText("Hello world"); 
     Log.d("test", "create fragment view"); 
     return tv; 
    } 

    @Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     menu.add("fragment"); 
     Log.d("test", "create fragment options menu"); 
    } 
} 

Układ jest tylko LinearLayout zrzucić fragmentu do :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/option_fragment_container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    > 
</LinearLayout> 

Bardzo proste prawda? Gdy uruchomię go uzyskać następujący wynik zgodnie z oczekiwaniami:

06-12 15:42:51.415: D/test(957): create activity 
06-12 15:42:51.446: D/test(957): create fragment 
06-12 15:42:51.446: D/test(957): create fragment view 
06-12 15:42:51.446: D/test(957): create Activity options menu 
06-12 15:42:51.446: D/test(957): create fragment options menu 

Teraz kiedy obrócić telefon mam jakieś dziwne zachowanie:

06-12 15:43:11.251: D/test(957): saving Activity state 
06-12 15:43:11.290: D/test(957): create fragment 
06-12 15:43:11.290: D/test(957): create activity 
06-12 15:43:11.306: D/test(957): create fragment view 
06-12 15:43:11.306: D/test(957): create Activity options menu 
06-12 15:43:11.306: D/test(957): create fragment options menu 
06-12 15:43:11.306: D/test(957): create Activity options menu 
06-12 15:43:11.306: D/test(957): create fragment options menu 

Dlaczego aktywność onCreateOptionMenu i fragment onCreateOptionsMenu nazwie dwa razy? Jeśli usunąć menu opcji z fragmentu dostaję 1 wezwanie do aktywności onCreateOptionsMenu zgodnie z oczekiwaniami:

06-12 15:50:03.610: D/test(1076): create fragment 
06-12 15:50:03.610: D/test(1076): create fragment view 
06-12 15:50:03.813: D/test(1076): create Activity options menu 
06-12 15:50:08.392: D/test(1076): saving Activity state // <-- rotate happens here 
06-12 15:50:08.446: D/test(1076): create fragment 
06-12 15:50:08.446: D/test(1076): create activity 
06-12 15:50:08.462: D/test(1076): create fragment view 
06-12 15:50:08.470: D/test(1076): create Activity options menu 

ja tego nie rozumiem i nikt inny nie wydaje się, że napotkał ten problem. Prawdziwy problem polega na tym, że mój SearchView nie jest w stanie odzyskać stanu po zmianie konfiguracji (obrót telefonu), ponieważ onCreateOptionMenu jest wywoływane dwa razy. Po raz pierwszy wydaje się, że ma stan, ale po raz drugi jest wyzerowany i zresetowany. Nie jestem w stanie dowiedzieć się, co robię źle.

Z góry dziękuję.

+0

Myślę, że najlepszym strzelcem byłoby się trzymać z kodem źródłowym i przejść przez nią z debuggera. Może to być błąd w systemie Android. –

+0

Nie zrobiłem żadnego postępu w tym problemie. Przeszedłem przez ten kod, ale nie jestem wystarczająco zaznajomiony z cyklem życia fragmentów/działań za kulisami, aby wiedzieć, co się dzieje i jaki może być problem. W tej chwili mam obejście, które jest dość "hacky", ale ruszam dalej. Jeśli ktoś wymyśli odpowiedź, daj mi znać. Dzięki! – Dave

+0

Mam dokładnie ten sam problem. 'onCreateOptionMenu' i' onPrepareOptionsMenu' są wywoływane dwukrotnie i po raz drugi resetują stan menu. Nie znalazłem jeszcze rozwiązania :( –

Odpowiedz

5

Myślę, że znalazłem odpowiedź na ten problem.

Weź wyglądać następująco:

https://stackoverflow.com/a/7225296/48468

Problem wydaje się być związane z faktem, że Android nie zniszczyć fragment, gdy działalność jest zniszczona (gdy urządzenie jest obrócony).

Zasadniczo I dodaje:

setRetainInstance(true); 

do mojego konstruktora fragmentu i problem go rozwiązać.

Mam nadzieję, że pomoże!

+3

Tak, dziękuję bardzo, to rozwiązało mój problem Co ciekawe, działanie ma również ten problem, jeśli fragment uczestniczy w menu opcji i nie wywołuje setRetainInstance (true) , nawet jeśli SearchView został dodany przez działanie.Jeśli usuniesz setHasOptionsMenu z fragmentu, działanie SearchView zachowuje się normalnie.Myślę, że ponieważ nowo dodany fragment powoduje, że działania naCreateOptionsMenu mają być wywołane ponownie. – Dave

2

@Gerardo Contijoch odpowiedź jest myląca, poza jednym faktem:

W przykładzie zarówno Activity i Fragment dostać zniszczone podczas obrotu i utworzony ponownie. To dlatego onCreateOptionsMenu() jest wywoływany dwa razy. To jest prawidłowe i oczekiwane zachowanie.

Przez setRetainInstance(true) mówisz Androidowi, aby nie niszczył fragmentu. Może się to przydać w przypadku fragmentu bez UI, który nie ma kontekstu działania (przydatny do koordynacji AsyncTasks i innych usługopodobnych rzeczy).

W innych przypadkach fragment ten potencjalnie prowadzi do wycieku pamięci, którego należy unikać.

0

Właśnie menu wyczyszczone przed pompowania i pracuje

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     menu.clear(); 
     inflater.inflate(R.menu.call_menu, menu); 
     super.onCreateOptionsMenu(menu, inflater); 

} 
Powiązane problemy