Nano Hash - криптовалюты, майнинг, программирование

ViewPager + FragmentPagerAdapter + Несколько фрагментов на вкладке

прежде всего, я прочитал несколько других тем, говорящих об этом, например: ViewPager

У меня есть собственный FragmentStackAdapter для управления всеми фрагментами моего приложения, окончательный запрос клиента — показать вкладки во всех приложениях, поэтому я решил реализовать SherlockActionBar + tabs + viewpager (для слайдов).

У меня есть следующая реализация FragmentStackAdapter:

public class FragmentStackAdapter extends FragmentPagerAdapter {

/**
 * Logging tag
 */
private final static String TAG = "FragmentStackAdapter";

/**
 * Fragment Manager
 */
private FragmentManager fm;

/**
 * Container of this adapter
 */
private ViewPager pager;

/**
 * Current tab position (SET THIS in the TAB LISTENER)
 */
private Integer currentTabPosition;

/**
 * Array of stacks to get fragment stack list.
 */
private SparseArray<LinkedList<Fragment>> stackFragments = new SparseArray<LinkedList<Fragment>>();

/**
 * Default constructor
 * @param fm FragmentManager
 */
public FragmentStackAdapter(FragmentManager fm, ViewPager pager) {

    super(fm);
    this.fm = fm;
    this.pager = pager;
}

public void addRootFragmentAtPosition(int tabPos, Fragment rootFragment) {

    if (tabPos > stackFragments.size() - 1) {
        stackFragments.put(tabPos, new LinkedList<Fragment>());
    }

    LinkedList<Fragment> stack = stackFragments.get(tabPos);
    stack.add(0, rootFragment);

}

public Fragment getRootFragment(int tabPos) {

    return stackFragments.get(tabPos).get(0);

}

public void addFragment(Fragment f) {

    startUpdate(pager);

    Tools.logLine(TAG, "addFragment(): Fragment:" + f + ", in position: " + currentTabPosition);
    LinkedList<Fragment> stack = stackFragments.get(currentTabPosition);
    Fragment last = stack.getLast();
    stack.addLast(f);

    fm.beginTransaction()
        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
        .remove(last)
        .add(pager.getId(), f)
        .commit();


    finishUpdate(pager);
    notifyDataSetChanged();

}

/**
 * Goes back in the current selected tab.
 * @return true if it goes back, false if cannot cause the stack is in the last element. Util for handle super.onPressback().
 */
public boolean back() {

    LinkedList<Fragment> stack = stackFragments.get(currentTabPosition);

    if (stack.size() > 1) {

        startUpdate(pager);

        Fragment currentFragment = stack.getLast();
        stack.removeLast();
        fm.beginTransaction()
            .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
            .remove(currentFragment)
            .add(pager.getId(), stack.getLast())
        .commit();

        notifyDataSetChanged();
        finishUpdate(pager);

        return true;

    }

    return false;
}

@Override
public int getCount() {
    return stackFragments.size();
}

@Override
public Fragment getItem(int pos) {

    LinkedList<Fragment> stack = stackFragments.get(pos);

    Fragment last = stack.getLast();

    Tools.logLine(TAG, "getItem() pos: " + pos + ", fragment:" + last.toString() + ", isV:" + last.isVisible() + ", isD:" + last.isDetached());
    return last;

}

@Override
public int getItemPosition(Object object) {

    int size = stackFragments.size();
    for (int i = 0 ; i < size ; i++) {

        int key = stackFragments.keyAt(i);
        LinkedList<Fragment> stack = stackFragments.get(key);

        if (stack.contains(object)) {

            int indexOf = stack.indexOf(object);

            // is root activity and is the current selected tab
            if (key == currentTabPosition && indexOf == 0) {

                return POSITION_NONE; // force reload this fragment

            } else if (indexOf == 0) { // if root and other, no changes

                return POSITION_UNCHANGED;

            }

            Tools.logLine(TAG, "getItemPos:, indexOf: " + indexOf + ", Object:" + object.toString());
            return indexOf; // return the pos of the activity

        }

    }

    Tools.logLine(TAG, "getItemPos: RETURN DEFAULTTTTT POSITION_NONE, " + object.toString()); 

    return POSITION_NONE; // the current item is not in the stack, so probabilly we removed it pressing back. Reload this tab will get another getItem and return the new corresponding item

}

@Override
public CharSequence getPageTitle(int position) {

    return "Near";

}

@Override
public long getItemId(int position) {

    LinkedList<Fragment> stack = stackFragments.get(position);
    Fragment f = stack.getLast();

    int rtnid = f.hashCode();

    Tools.logLine(TAG, "getItemId() for pos: " + position + ", Fragment: "+ f  +", rtnId: " + rtnid + ", hex: " + Integer.toString(rtnid, 16));

    return rtnid;

}

public void setCurrentTabPostion(int currentTabPosition) {
    this.currentTabPosition = currentTabPosition;
}
    }

И вот как я инициализирую свою MainActivity:

// Назначаем пользовательский интерфейс viewPager = (ViewPager)findViewById(R.id.pager);

    // Configure the StackAdapter
    fragmentAdapter = new FragmentStackAdapter(getSupportFragmentManager(), viewPager);
    fragmentAdapter.addRootFragmentAtPosition(TIMELINE_TAG, new TimelineActivity());
    fragmentAdapter.addRootFragmentAtPosition(NEAR_TAG, new NearFragment());

Я думаю, что это работает нормально, когда я вызываю fragmentAdapter.addFragment(). Он показывает новый фрагмент в ранее загруженном фрагменте, но не работает, когда я обрабатываю метод «back()», показывающий эту трассировку стека:

        did=1: thread exiting with uncaught exception (group=0x400205a0)
         FATAL EXCEPTION: main
         java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
            at android.view.ViewGroup.addViewInner(ViewGroup.java:2062)
            at android.view.ViewGroup.addView(ViewGroup.java:1957)
            at android.view.ViewGroup.addView(ViewGroup.java:1914)
            at android.view.ViewGroup.addView(ViewGroup.java:1894)
            at android.support.v4.app.NoSaveStateFrameLayout.wrap(NoSaveStateFrameLayout.java:40)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:875)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1083)
            at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:635)
            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1431)
            at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:431)
            at com.bbva.tweetmeter.ui.FragmentStackAdapter.getItemPosition(FragmentStackAdapter.java:311)
            at android.support.v4.view.ViewPager.dataSetChanged(ViewPager.java:712)
            at android.support.v4.view.ViewPager$PagerObserver.onChanged(ViewPager.java:2519)
            at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:31)
            at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:276)
            at com.bbva.tweetmeter.ui.FragmentStackAdapter.back(FragmentStackAdapter.java:154)
            at com.bbva.tweetmeter.ui.MainActivity.onBackPressed(MainActivity.java:210)
            at android.app.Activity.onKeyUp(Activity.java:1985)
            at android.view.KeyEvent.dispatch(KeyEvent.java:1513)
            at android.app.Activity.dispatchKeyEvent(Activity.java:2210)
            at com.actionbarsherlock.app.SherlockFragmentActivity.dispatchKeyEvent(SherlockFragmentActivity.java:122)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1769)
            at android.view.ViewRoot.deliverKeyEventToViewHierarchy(ViewRoot.java:2716)
            at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2688)
            at android.view.ViewRoot.handleMessage(ViewRoot.java:1969)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:143)
            at android.app.ActivityThread.main(ActivityThread.java:4293)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:507)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
            at dalvik.system.NativeStart.main(Native Method)

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

Не стесняйтесь спрашивать, если я не правильно объяснил


  • ОБНОВЛЕНИЕ Когда я вызываю метод back(), я вижу, что основной фрагмент уже прикреплен. Я не знаю, почему, потому что в методе addFragment я уже удалил... 10.10.2012

Ответы:


1

У меня была такая же проблема, когда я использовал

View res = inflater.inflate(R.layout.fragment_guide_search, container);

внутри Fragment.onCreateView(...

Вы должны позвонить

View res = inflater.inflate(R.layout.fragment_guide_search, container, false);

or

View res = inflater.inflate(R.layout.fragment_guide_search, null);

ВНИМАНИЕ С ПОСЛЕДНИМ ВАРИАНТОМ. Чтобы понять, что именно происходит, прочитайте эту замечательную статью: http://www.doubleencore.com/2013/05/layout-inflation-as-intended./

22.01.2013

2

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

11.10.2012
  • вот альтернативное решение: stackoverflow.com/a/15336705/878126 или вы можете просто использовать setOffscreenPageLimit : developer.android.com/reference/android/support/v4/ просмотр/ 11.03.2013

  • 3

    У меня была такая же проблема при использовании FragmentPagerAdapter, если вы работаете с FragmentPagerAdapter, просто используйте метод destroyItem внутри FragmentPagerAdapter.

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) 
    {
            FragmentTransaction ft=fm.beginTransaction();
            ft.remove((Fragment) object);
            ft.commit();
    }
    

    setOffscreenPageLimit(int limit) потребляет больше памяти и в некоторых случаях не работает идеально. его состояние сохранения на любой стороне см. в описании.setOffscreenPageLimit(int limit) — устанавливает количество страниц, которые должны сохраняться по обе стороны от текущей страницы в иерархии представлений в состоянии ожидания.

    17.01.2015
    Новые материалы

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

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

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

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..