Подтвердить что ты не робот

Избегайте воссоздания одного и того же вида при переключении табуляции

Ток, у меня есть 2 Fragments, который может переключаться через вкладку ActionBar.

    getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    ActionBar.Tab newTab = getSupportActionBar().newTab();
    newTab.setText("history");
    newTab.setTabListener(new TabListenerHistoryFragment>(this, "history",
        HistoryFragment.class));

 @Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
    // Check if the fragment is already initialized
    if (mFragment == null) {

        // If not, instantiate and add it to the activity
        mFragment = Fragment.instantiate(mActivity, mClass.getName());
        mFragment.setRetainInstance(true);
        ft.add(android.R.id.content, mFragment, mTag);
    } else {
        // If it exists, simply attach it in order to show it
        ft.attach(mFragment);
    }        
}

Я понимаю, что в первый раз, когда мой Activity (эта активность содержит 2 фрагмента) запускается, методы Fragment s 'будут вызываться в следующей последовательности.

onCreate -> onCreateView -> onStart

Когда я выполняю переключение Tab, а затем Tab переключается обратно на тот же фрагмент, снова будут вызваны следующие методы.

onCreateView -> onStart

Я просто хочу сохранить одно и то же состояние представления GUI, когда Tab снова переключается.

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

Я знаю, что я могу сохранять/восстанавливать простые переменные, используя следующий метод при переключении Tab

Андроид-фрагмент. Как сохранить состояния просмотров во фрагменте, когда другой фрагмент нажат поверх него.

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

Я пробую следующий подход. Конечно, это не сработает, так как я получаю следующую ошибку времени выполнения.

public class HistoryFragment extends Fragment {
    View view = null;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (this.view != null) {
            return this.view;
        }
        this.view = inflater.inflate(R.layout.history_activity, container, false); 
    }
}

java.lang.IllegalStateException: указанный дочерний элемент уже имеет родителя. Сначала вы должны вызвать removeView() для родительского родителя.

Я понимаю, что следующий демонстрационный пример может сохранить состояние своего фрагмента GUI (например, положение вертикальной прокрутки списка) при переключении Tab. Но я думаю, возможно, это потому, что они используют ListFragment? Поскольку я не считаю, что они выполняют какую-либо специальную обработку для сохранения состояния GUI.

  • com.example.android.apis.app.FragmentTabs
  • com.example.android.apis.app.LoaderCursor.CursorLoaderListFragment

Могу ли я узнать, как я могу избежать воссоздания одного и того же вида при переходе на вкладку?

4b9b3361

Ответ 1

У меня была та же проблема, и я попытался выполнить предложение в сообщении об ошибке. Я попробовал следующий код, и это сработало для меня.

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state)  {
     if (mMyView == null) {
         mMyView = new MyView(getActivity());
     } else {
         ((ViewGroup) mMyView.getParent()).removeView(mMyView);
     }

     return mPuzzleView; 
}

Ответ 2

Я начал искать простое решение для этого много часов назад и, наконец, наткнулся на ответ от @roger, который спас мне много волос....

При использовании ViewPager в других реализациях я могу просто вызвать:

mViewPager.setOffscreenPageLimit(//number of pages to cache);

Итак, я был очень удивлен, что мне потребовалось столько часов, чтобы это решить. Пример, который он дал, был не совсем ясен, поэтому, так для полноты, вот код, который я использую для фрагментов в FragmentTabHost

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentExample extends Fragment {

    private View rootView;

    public FragmentExample() {
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {

        if (rootView == null) {

            rootView = inflater.inflate(R.layout.fragment_example_layout, container, false);

            // Initialise your layout here

        } else {
            ((ViewGroup) rootView.getParent()).removeView(rootView);
        }

        return rootView;
    }
}

Я искал следующие ключевые фразы, которые я добавляю здесь, в надежде, что я могу спасти кого-то из разочарования, которое я только что испытал!


FragmentTabHost сохранить состояние фрагмента

Воспроизведение фрагментов FragmentTabHost

Фрагменты фрагмента фрагмента

FragmentTabHost onCreateView Фрагмент уничтожен


Ответ 3

Следующее решение работает для меня. Это предотвращает вызов Fragment onCreateView при переключении вкладок.

Действие onCreate должно добавить все фрагменты и скрыть все, кроме одного для первой вкладки:

ft.add(R.id.fragment_content, secondTabFragment);
ft.hide(secondTabFragment);
ft.add(R.id.fragment_content, firstTabFragment);
ft.show(firstTabFragment);
ft.commit();
currentFragment = firstTabFragment;

Активность onTabSelected должна просто скрыть текущий фрагмент и показать фрагмент, соответствующий выбранной вкладке.

ft.hide(currentFragment);
ft.show(chosenFragment);
ft.commit();
currentFragment = chosenFragment;

Остерегайтесь того, что изменение ориентации устройства приведет к перезапуску вашего действия и последующему восстановлению фрагментов. Вы можете избежать этого, добавив этот configChanges в свой манифест:

<activity android:configChanges="keyboardHidden|orientation" ...

Ответ 4

View mMyView = null;     
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state)  {
         if (state == null) {
             mMyView = new MyView(getActivity());
         } else {
             container.removeView(mMyView);
         }

         return mMyView; 
    }

Ответ 5

Update

Я просто избегаю этой проблемы, используя ViewPager вместо вкладки ActionBar.

Ответ 6

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

fragmentManager.executePendingTransactions();

это решает проблему для меня

@Override
public void onTabelected(Tab tab, FragmentTransaction ft, FragmentManager fm) {
    fm.executePendingTransactions(); // **execute the pending transactions before adding another fragment.
    if (mFragment == null) {
        mFragment = Fragment.instantiate(mContext, mFragmentName);
        ft.replace(android.R.id.tabcontent, mFragment, mTag);
    } else {
        ft.attach(mFragment);
    }
}