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.


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

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) {
    

miło Save my time wah
— Arjun saini
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.