Niezawodny sposób obsługi Fragmentu przy zmianie orientacji

87
public class MainActivity extends Activity implements MainMenuFragment.OnMainMenuItemSelectedListener {

 @Override
 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager
            .beginTransaction();

    // add menu fragment
    MainMenuFragment myFragment = new MainMenuFragment();
    fragmentTransaction.add(R.id.menu_fragment, myFragment);

    //add content
    DetailPart1 content1= new DetailPart1 ();
    fragmentTransaction.add(R.id.content_fragment, content1);
    fragmentTransaction.commit();

}
public void onMainMenuSelected(String tag) {
  //next menu is selected replace existing fragment
}

Muszę wyświetlić obok siebie dwa widoki list, menu po lewej i jego zawartość po prawej stronie. Domyślnie wybrane jest pierwsze menu, a jego zawartość jest wyświetlana po prawej stronie. Fragment, który wyświetla zawartość, jest następujący:

public class DetailPart1 extends Fragment {
  ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String, String>>();
  ListAdapter adap;
  ListView listview;

  @Override
  public void onActivityCreated(Bundle savedInstanceState) {
      super.onActivityCreated(savedInstanceState);

       if(savedInstanceState!=null){
        myList = (ArrayList)savedInstanceState.getSerializable("MYLIST_obj");
        adap = new LoadImageFromArrayListAdapter(getActivity(),myList );
        listview.setAdapter(adap);
       }else{
        //get list and load in list view
        getlistTask = new GetALLListTasks().execute();
    }


     @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.skyview_fragment, container,false);
           return v;
        }


     @Override
      public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
          outState.putSerializable("MYLIST_obj", myList );
        }
    }

OnActivityCreated i onCreateView są wywoływane dwukrotnie . Istnieje wiele przykładów użycia fragmentów. Ponieważ jestem początkującym w tym temacie, nie mogę odnieść tego przykładu do mojego problemu. Potrzebuję niezawodnego sposobu radzenia sobie ze zmianą orientacji. NIE zadeklarowałem android:configChangesw pliku manifestu. Potrzebuję działania zniszczenia i odtworzenia, aby móc używać innego układu w trybie poziomym.

user1811741
źródło
Zazwyczaj zmiany orientacji fragmentów są obsługiwane bez potrzeby wykonywania jakichkolwiek czynności. Jaki jest więc problem, który napotykasz, zmieniając orientację?
Alexander Kulyakhtin
Alex Potrzebuję fragmentu klasy DetailPart1, aby wyświetlić układ z listView w trybie pionowym i układ z widokiem siatki w trybie poziomym. W tym celu muszę za każdym razem odtworzyć fragment, ale nie chcę ponownie ładować tych samych rekordów, więc przechowuj je w onSaveInstanceState. Ale powyższy kod dwukrotnie odtwarza część DetailPart1, muszę znać brakujący kod, który sprawia, że ​​działa zgodnie z oczekiwaniami
user1811741

Odpowiedzi:

132

Za każdym razem, gdy obracasz ekran w swojej aktywności, tworzysz nowy fragment, onCreate();ale jednocześnie zachowujesz stare super.onCreate(savedInstanceState);. Więc może ustaw tag i znajdź fragment, jeśli istnieje, lub przekaż pakiet zerowy do super.

Zajęło mi to trochę czasu, aby się tego nauczyć i może to być naprawdę dziwne, gdy pracujesz z takimi rzeczami, jak przeglądarka.

Polecam przeczytać o fragmentach dodatkowy czas, ponieważ omawiamy dokładnie ten temat.

Oto przykład postępowania z fragmentami przy zwykłej zmianie orientacji:

Aktywność :

public class MainActivity extends FragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            TestFragment test = new TestFragment();
            test.setArguments(getIntent().getExtras());
            getSupportFragmentManager().beginTransaction().replace(android.R.id.content, test, "your_fragment_tag").commit();
        } else {
            TestFragment test = (TestFragment) getSupportFragmentManager().findFragmentByTag("your_fragment_tag");
        }
    }
}

Fragment :

public class TestFragment extends Fragment {

    public static final String KEY_ITEM = "unique_key";
    public static final String KEY_INDEX = "index_key";
    private String mTime;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);

        if (savedInstanceState != null) {
            // Restore last state
            mTime = savedInstanceState.getString("time_key");
        } else {
            mTime = "" + Calendar.getInstance().getTimeInMillis();
        }

        TextView title = (TextView) view.findViewById(R.id.fragment_test);
        title.setText(mTime);

        return view;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("time_key", mTime);
    }
}
Warpzit
źródło
dzięki Warpzit za twój wysiłek, ale będę zadowolony, jeśli wyjaśnisz w kodzie swój punkt. Jak zmienić mój kod, aby obsłużyć zmianę orientacji bez ponownego ładowania fragmentu.
user1811741
1
Dlatego potrzebuję zmiany układu fragmentu w orientacji, ale nie chcę ponownie ładować wszystkich rekordów, co zrobiłem to 1. dodaj android: configchanges = "orientacja" w manifeście 2. zastąpienie onConfigurationChanged we fragmencie i wykryj orientację i ukryj / pokaż widok listy lub widok siatki w zależności od orientacji. Czy to jest właściwy sposób?
user1811741
@ user1811741 zaktualizowany o przykład. Mam nadzieję, że wszystko wyjaśnia.
Warpzit
@Warpzit Jak można obsłużyć ten sam scenariusz w przypadku implementacji fragmentu ViewPager, ponieważ ViewPager zajmie się wszystkimi wyświetlanymi fragmentami .. wszelkie sugestie.
CoDe
1
@Shubh wierzę, że viewpager radzi sobie z tym prawidłowo, jeśli nie, będziesz musiał zastąpić implementację getItem, aby pasowała do twoich potrzeb. Mam nadzieję, że to wskazało ci właściwy kierunek, jeśli nie postawiłem właściwego pytania :)
Warpzit.
21

Dobre wytyczne dotyczące zachowywania danych między zmianami orientacji a odtwarzaniem aktywności można znaleźć w wytycznych dotyczących systemu Android .

Podsumowanie:

  1. spraw, aby twój fragment był zachowany:

    setRetainInstance(true);
    
  2. Utwórz nowy fragment tylko w razie potrzeby (lub przynajmniej weź z niego dane)

    dataFragment = (DataFragment) fm.findFragmentByTag("data");
    
    // create the fragment and data the first time
    if (dataFragment == null) {
    
Sergej Werfel
źródło
miło Save my time wah
Arjun saini