android fragment - jak zapisać Stany widoków w fragmencie, gdy inny fragment jest popychany na niego

W Androidzie fragment (powiedzmy FragA) jest dodawany do backstacka, a inny fragment (powiedzmy FragB) pojawia się na górze. Teraz po uderzeniu z powrotem FragA wchodzi na szczyt i onCreateView() jest wywoływany. Teraz miałem FragA w określonym stanie, zanim FragB zostałem zepchnięty na wierzch.

Moje pytanie brzmi: Jak mogę przywrócić FragA do poprzedniego stanu ? Czy istnieje sposób na zapisanie stanu (jak np. w pakiecie), a jeśli tak, to jaką metodę powinienem nadpisać ?

Author: pankajagarwal, 2011-07-22

11 answers

W fragment guide Fragmentlisty przykład można znaleźć:

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("curChoice", mCurCheckPosition);
}

Które możesz użyć później w ten sposób:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (savedInstanceState != null) {
        // Restore last state for checked position.
        mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
    }
}

Jestem początkujący we fragmentach, ale wydaje się, że rozwiązanie twojego problemu ;) OnActivityCreated jest wywoływany po powrocie fragmentu z tylnego stosu.

 99
Author: ania,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-07 19:40:59

Fragment onSaveInstanceState(Bundle outState) nigdy nie zostanie wywołany, dopóki aktywność fragmentu nie wywoła go na sobie i dołączonych fragmentach. Tak więc ta metoda nie zostanie wywołana, dopóki coś (zazwyczaj obrót) wymusi aktywność SaveInstanceState i przywróci ją później. Ale jeśli masz tylko jedną aktywność i duży zestaw fragmentów wewnątrz niej (z intensywnym użyciem replace) i aplikacja działa tylko w jednym działaniu orientacyjnym onSaveInstanceState(Bundle outState) może nie być wywołana przez długi czas.

Znam trzy możliwe obejścia.

The pierwszy:

Użyj argumentów fragmentu do przechowywania ważnych danych:

public class FragmentA extends Fragment {
    private static final String PERSISTENT_VARIABLE_BUNDLE_KEY = "persistentVariable";

    private EditText persistentVariableEdit;

    public FragmentA() {
        setArguments(new Bundle());
    }

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

        persistentVariableEdit = (EditText) view.findViewById(R.id.editText);

        TextView proofTextView = (TextView) view.findViewById(R.id.textView);

        Bundle mySavedInstanceState = getArguments();
        String persistentVariable = mySavedInstanceState.getString(PERSISTENT_VARIABLE_BUNDLE_KEY);

        proofTextView.setText(persistentVariable);


        view.findViewById(R.id.btnPushFragmentB).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager()
                        .beginTransaction()
                        .replace(R.id.frameLayout, new FragmentB())
                        .addToBackStack(null)
                        .commit();
            }
        });

        return view;
    }

    @Override
    public void onPause() {
        super.onPause();
        String persistentVariable = persistentVariableEdit.getText().toString();

        getArguments().putString(PERSISTENT_VARIABLE_BUNDLE_KEY, persistentVariable);
    }
}
Drugi, ale mniej pedantyczny sposób - przechowuj zmienne w singletonach

Trzeci-nie replace() fragmenty, ale add()/show()/hide() zamiast nich.

 75
Author: Fyodor Volchyok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-01 07:51:31

Zauważ, że jeśli pracujesz z fragmentami za pomocą Viewpagera, jest to całkiem proste. Wystarczy wywołać tę metodę: setOffscreenPageLimit().

Zgodnie z docs:

Ustawia liczbę stron, które mają być zachowane po obu stronach bieżącej strony w hierarchii widoku w stanie bezczynności. Strony poza tym limitem zostaną odtworzone z adaptera w razie potrzeby.

Simmilar problem tutaj

 20
Author: e_v_e,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:24

Po prostu nadmuchaj Widok.

Exemple:

public class AFragment extends Fragment {

private View mRootView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if(mRootView==null){
        mRootView = inflater.inflate(R.id.fragment_a, container, false);
        //......
    }
    return mRootView;
}

}

 11
Author: Lym Zoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-11 06:48:38

Pracowałem z problemem bardzo podobnym do tego. Ponieważ wiedziałem, że często będę wracał do poprzedniego fragmentu, sprawdziłem, czy fragment .isAdded() jest prawdziwy, a jeśli tak, to zamiast robić transaction.replace() po prostu robię transaction.show(). Dzięki temu fragment nie jest odtwarzany, jeśli jest już na stosie - nie jest konieczne zapisywanie stanu.

Fragment target = <my fragment>;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
if(target.isAdded()) {
    transaction.show(target);
} else {
    transaction.addToBackStack(button_id + "stack_item");
    transaction.replace(R.id.page_fragment, target);
}
transaction.commit();

Inną rzeczą, o której należy pamiętać, jest to, że chociaż zachowuje to naturalny porządek dla samych fragmentów, nadal możesz potrzebować obsługi sama aktywność jest niszczona i odtwarzana po zmianie orientacji (config). Aby obejść to w AndroidManifest.xml dla Twojego węzła:

android:configChanges="orientation|screenSize"
[[6]}W Androidzie 3.0 i wyższych, screenSize jest najwyraźniej wymagane.

Powodzenia

 8
Author: rmirabelle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-26 14:29:54

Najlepsze rozwiązanie jakie znalazłem jest poniżej:

OnSavedInstanceState (): zawsze wywoływana wewnątrz fragmentu, gdy aktywność ma się wyłączyć(przenieść aktywność z jednej do drugiej lub zmienić konfigurację). Jeśli więc wywołujemy wiele fragmentów na tej samej aktywności, musimy użyć następującego podejścia:

Użyj ondestroyview () fragmentu i zapisz cały obiekt wewnątrz tej metody. Wtedy Onactivitycreated (): sprawdza czy obiekt jest null czy nie (ponieważ metoda ta wywołuje za każdym razem). Teraz Przywróć stan obiektu tutaj.

Its works always!

 5
Author: Aman Goel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-08 11:51:41

Jeśli obsługujesz zmiany konfiguracyjne w aktywności fragmentu określonej w manifeście Androida, tak jak to

<activity
    android:name=".courses.posts.EditPostActivity"
    android:configChanges="keyboardHidden|orientation"
    android:screenOrientation="unspecified" />

Wtedy onSaveInstanceState fragmentu nie zostanie wywołany, a savedInstanceState Obiekt zawsze będzie null.

 4
Author: Brook Oldre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-03 11:03:00

Użyłem podejścia hybrydowego dla fragmentów zawierających widok listy. Wydaje się być wydajny, ponieważ nie zastępuję bieżącego fragmentu, ale raczej dodaję nowy fragment i ukrywam bieżący. Mam następującą metodę w działaniu, która hostuje moje fragmenty:

public void addFragment(Fragment currentFragment, Fragment targetFragment, String tag) {
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    transaction.setCustomAnimations(0,0,0,0);
    transaction.hide(currentFragment);
    // use a fragment tag, so that later on we can find the currently displayed fragment
    transaction.add(R.id.frame_layout, targetFragment, tag)
            .addToBackStack(tag)
            .commit();
}

Używam tej metody w moim fragmencie (zawierającym widok listy) za każdym razem, gdy element listy jest kliknięty/stuknięty (a więc muszę uruchomić / wyświetlić fragment szczegółów):

FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
SearchFragment currentFragment = (SearchFragment) fragmentManager.findFragmentByTag(getFragmentTags()[0]);
DetailsFragment detailsFragment = DetailsFragment.newInstance("some object containing some details");
((MainActivity) getActivity()).addFragment(currentFragment, detailsFragment, "Details");

getFragmentTags() zwraca tablicę łańcuchów, które Używam jako znaczników dla różnych fragmentów, gdy dodaję nowy fragment (patrz metoda transaction.add w metodzie addFragment powyżej).

W fragmencie zawierającym widok listy robię to w jego metodzie onPause ():

@Override
public void onPause() {
    // keep the list view's state in memory ("save" it) 
    // before adding a new fragment or replacing current fragment with a new one
    ListView lv =  (ListView) getActivity().findViewById(R.id.listView);
    mListViewState = lv.onSaveInstanceState();
    super.onPause();
}

Następnie w onCreateView fragmentu (właściwie w metodzie, która jest wywoływana w onCreateView), przywracam stan:

// Restore previous state (including selected item index and scroll position)
if(mListViewState != null) {
    Log.d(TAG, "Restoring the listview's state.");
    lv.onRestoreInstanceState(mListViewState);
}
 0
Author: Javad Sadeqzadeh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-29 20:26:39

Nie sądzę {[0] } jest dobrym rozwiązaniem. to po prostu użyć do aktywności, która została zniszczona.

Od Androida 3.0 Fragmen został menadżerem przez FragmentManager, warunkiem jest: jedna aktywność mapująca fragmenty manny, gdy fragment zostanie dodany (nie zastąpi: zostanie odtworzony) w backstacku, Widok zostanie destored. po powrocie do ostatniego, wyświetli się jak wcześniej.

Więc myślę, że fragment i transakcja są wystarczająco dobre, aby sobie z tym poradzić.
 0
Author: smallfatter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-20 03:43:46

W końcu po wypróbowaniu wielu z tych skomplikowanych rozwiązań, ponieważ musiałem tylko zapisać / przywrócić pojedynczą wartość w moim fragmencie( zawartość EditText), i chociaż nie jest to najbardziej eleganckie rozwiązanie, stworzenie SharedPreference i przechowywanie mojego stanu tam działało dla mnie

 0
Author: VMMF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-25 21:16:57
private ViewPager viewPager;
viewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // on changing the page
            // make respected tab selected
            actionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    });
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
    // on tab selected
    // show respected fragment view
    viewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
 -1
Author: Sathish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-09 13:59:45