Android fragment - как сохранить состояния представлений во фрагменте, когда другой фрагмент помещается поверх него



в android, фрагмент (скажем FragA) добавляется в backstack и другой фрагмент (скажем FragB) выходит на вершину. Теперь на ответный удар FragA доходит до вершины и onCreateView() называется. Теперь у меня было FragA в определенном состоянии перед FragB его толкнули сверху.



мой вопрос: как я могу восстановить FragA в прежнее состояние ? Есть ли способ сохранить состояние (например, в пакете), и если да, то какой метод я должен переопределить ?

938   11  

11 ответов:

на руководство фрагмент пример FragmentList вы можете найти:

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

, который можно использовать позже, как это:

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

Я новичок в фрагментах, но это похоже на решение вашей проблемы ;) OnActivityCreated вызывается после возврата фрагмента из заднего стека.

фрагмента!--1--> никогда не будет вызван, если активность фрагмента не вызовет его на себя и прикрепленные фрагменты. Таким образом, этот метод не будет вызываться до тех пор, пока что-то (обычно вращение) не заставит активность SaveInstanceState и восстановить его позже. Но если у вас есть только одно действие и большой набор фрагментов внутри него (с интенсивным использованием replace) и приложение работает только в одной ориентации деятельности onSaveInstanceState(Bundle outState) не может быть привлечен в течение длительного времени.

Я знаю три возможных обходные приемы.

первый:

используйте аргументы фрагмента для хранения важных данных:

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

второй, но менее педантичный способ - держите переменные в синглетах

третий - не replace() фрагменты, но add()/show()/hide() их вместо.

просто обратите внимание, что если вы работаете с фрагментами с помощью ViewPager, это довольно легко. Вам нужно только вызвать этот метод: setOffscreenPageLimit().

Accordign к документам:

установите количество страниц, которые должны быть сохранены на любой стороне текущей страницы в иерархии представлений в состоянии ожидания. Страницы за пределами этого предела будут воссозданы из адаптера при необходимости.

аналогичная проблема здесь

просто раздуть свой взгляд на этот раз.

пример следующим образом:

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

}

Я работал с проблемой, очень похожей на эту. Поскольку я знал, что часто буду возвращаться к предыдущему фрагменту, я проверил, есть ли фрагмент .isAdded() было правдой, и если да, то вместо того, чтобы делать transaction.replace() Я просто делаю transaction.show(). Это предотвращает повторное создание фрагмента, если он уже находится в стеке-сохранение состояния не требуется.

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

еще одна вещь, чтобы иметь в виду, что в то время как это сохраняет естественный порядок для самих фрагментов, вы все еще можете нужно обрабатывать саму активность, которая уничтожается и воссоздается при изменении ориентации (конфигурации). Чтобы обойти это в AndroidManifest.xml для вашего узла:

android:configChanges="orientation|screenSize"

в Android 3.0 и выше,screenSize это, видимо, требуется.

удачи

лучшее решение, которое я нашел ниже:

onSavedInstanceState (): всегда вызывается внутри фрагмента, когда действие собирается завершить работу(переместить действие из одного в другой или изменения конфигурации). Так что если мы вызываем несколько фрагментов на одной и той же активности, то мы должны использовать следующий подход:

используйте OnDestroyView () фрагмента и сохраните весь объект внутри этого метода. Затем OnActivityCreated (): проверьте, что если объект null или нет(потому что этот метод вызывает каждый раз.) Теперь восстановите состояние объекта здесь.

его работы всегда!

Если вы обрабатываете изменения конфигурации в своей активности фрагмента, указанной в манифесте android, как это

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

тут onSaveInstanceState из фрагмента не будет вызываться и savedInstanceState объект всегда будет null.

я использовал гибридный подход для фрагментов, содержащих представления списка. Кажется, он работает, так как я не заменяю текущий фрагмент, а скорее добавляю новый фрагмент и скрываю текущий. У меня есть следующий метод в деятельности, которая содержит мои фрагменты:

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

Я использую этот метод в моем фрагменте (содержащем представление списка) всякий раз, когда элемент списка нажат/нажат (и поэтому мне нужно запустить/отобразить фрагмент сведений):

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() возвращает массив строк, которые я использую в качестве тегов для различных фрагментов при добавлении нового фрагмента (см. transaction.add метод addFragment способ выше).

во фрагменте, содержащем представление списка, я делаю это в своем методе 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();
}

затем в onCreateView фрагмента (на самом деле в методе, который вызывается в onCreateView), я восстанавливаю состояние:

// Restore previous state (including selected item index and scroll position)
if(mListViewState != null) {
    Log.d(TAG, "Restoring the listview's state.");
    lv.onRestoreInstanceState(mListViewState);
}

Я не думаю, что onSaveInstanceState - Это хорошее решение. его просто используют для деятельности, которая была уничтожена.

из android 3.0 Fragmen был менеджером FragmentManager, условие: одно сопоставление фрагментов Мэнни, когда фрагмент добавляется (не заменяется: он будет воссоздан) в backStack, представление будет destored. вернувшись к последнему, он будет отображаться как и прежде.

поэтому я думаю, что fragmentManger и транзакция достаточно хороши, чтобы справиться с этим.

в конце концов, после попытки многих из этих сложных решений, поскольку мне нужно было только сохранить / восстановить одно значение в моем фрагменте (содержимое EditText), и хотя это может быть не самое элегантное решение, создание SharedPreference и сохранение моего состояния там работали для меня

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

Comments

    Ничего не найдено.