Android ограничивает фрагменты только один раз, чтобы вернуться в стек

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

Например, есть 3 фрагмента. А, В, С

Образец фрагмента: ABCBACAC

На выходе пресса должно быть: CAB-выход

Но я получу этот паттерн - CACABCBA-выход

Вот код, который я использую

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()){
        case R.id.nav_home:
            mFragment = getSupportFragmentManager().findFragmentByTag("Fragment_Home");
            if(!(mFragment!=null && mFragment.isVisible())){
                mFragmentManager.popBackStackImmediate("Fragment_Home", FragmentManager.POP_BACK_STACK_INCLUSIVE);
                mFragmentTransaction = mFragmentManager.beginTransaction();
                mFragmentTransaction.replace(R.id.container, new HomeFragment(), "Fragment_Home").addToBackStack("Fragment_Home").commit();
            }
            return true;
        case R.id.nav_account:
            mFragment = getSupportFragmentManager().findFragmentByTag("Fragment_Account");
            if(!(mFragment != null && mFragment.isVisible())){
                mFragmentManager.popBackStackImmediate("Fragment_Account", FragmentManager.POP_BACK_STACK_INCLUSIVE);
                mFragmentTransaction = mFragmentManager.beginTransaction();
                mFragmentTransaction.replace(R.id.container, new AccountFragment(), "Fragment_Account").addToBackStack("Fragment_Account").commit();
            }
            return true;
        case R.id.nav_category:
            mFragment = getSupportFragmentManager().findFragmentByTag("Fragment_Category");
            if(!(mFragment != null && mFragment.isVisible())){
                mFragmentManager.popBackStackImmediate("Fragment_Category", FragmentManager.POP_BACK_STACK_INCLUSIVE);
                mFragmentTransaction = mFragmentManager.beginTransaction();
                mFragmentTransaction.replace(R.id.container, new CategoryFragment(), "Fragment_Category").addToBackStack("Fragment_Category").commit();
            }
            return true;
    }
    return false;
}

@Override
public void onBackPressed() {
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        mDrawerLayout.closeDrawer(GravityCompat.START);           
    }
    else if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
        getSupportFragmentManager().popBackStack();
    }
    else if (doubleBackToExitPressedOnce) {
        finishAffinity();
    }
    else {
        this.doubleBackToExitPressedOnce = true;
        Toast.makeText(this, "Please BACK again to exit", Toast.LENGTH_SHORT).show();
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                doubleBackToExitPressedOnce = false;
            }
        }, 2000);
    }
}

Дайте мне понять, что не так с моим кодом. Любая помощь будет оценена.

2 ответа

Для этой проблемы я рекомендую использовать Viewpager вместо Back-stack фрагмента. Во-первых, я скажу вам, почему вы не должны использовать Backstack Fragment. Я полагаю, в вашем коде, когда ваша деятельность создается. Вы немедленно перейдете к своему Первому фрагменту. Например: A - B - C - C - C - C - C или A - B - C - A -B -C - A -C -B. Это удалит фрагмент backstack, как то, что вы сказали, каждый раз, когда вы щелкаете фрагмент снова, вы создаете новый. Вот еще один способ использовать Viewpager, сделать UX намного лучше. Во-первых, я настроил свой собственный FragmentStatePagerAdapter для лучшей производительности

public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
    // Sparse array to keep track of registered fragments in memory
    private SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

    public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    // Register the fragment when the item is instantiated
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }

    // Unregister when the item is inactive
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        registeredFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    // Returns the fragment for the position (if instantiated)
    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }
}

Давай создадим CustomViewPager

public class CustomViewPager extends ViewPager {

    public CustomViewPager(Context context) {
        super(context);
        setMyScroller();
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setMyScroller();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        // Never allow swiping to switch between pages
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Never allow swiping to switch between pages
        return false;
    }

    //down one is added for smooth scrolling

    private void setMyScroller() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            scroller.set(this, new MyScroller(getContext()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class MyScroller extends Scroller {
        public MyScroller(Context context) {
            super(context, new DecelerateInterpolator());
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/);
        }
    }
}

положить его в свой XML файл как это:

<YOUR_PACKAGE_NAME.CustomViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
       />

Это адаптер ViewPager:

public class ViewPagerAdapter extends SmartFragmentStatePagerAdapter {
    private static int NUM_ITEMS = 3;
    private BaseFragment mFragment1, mFragment2, mFragment3;

    public ViewPagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);

        mFragment1= Fragment1.newInstance(0, FRAGMENT_TAG_1);
        mFragment2= Fragment2.newInstance(1, FRAGMENT_TAG_2);
        mFragment3= Fragment3.newInstance(2, FRAGMENT_TAG_3);
    }


    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return mFragment1;
            case 1:
                return mFragment2;
            case 2:
                return mFragment3;
            default:
                return null;
        }
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public int getItemPosition(Object object) {
            return POSITION_NONE;
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

}

В вашей деятельности пусть init это в onCreateView()

        mViewPager = (CustomViewPager) findViewById(R.id.viewPager);
        mViewPagerAdapter = new ViewPagerAdapter(mFragmentManager);
        mViewPager.setAdapter(mViewPagerAdapter);
        mFrameLayout.setVisibility(View.GONE);
        mViewPager.setVisibility(View.VISIBLE);
        mViewPager.setSaveEnabled(true);

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

mViewPager.setCurrentItem(NUMBER_OF_TIME);

Что вы должны сделать, так это объявить действия A,B и C как "singleTop"

Если экземпляр действия уже существует в верхней части текущей задачи, система направляет намерение этому экземпляру посредством вызова его метода onNewIntent(), а не создает новый экземпляр действия. Действие может быть создано несколько раз, каждый экземпляр может принадлежать разным задачам, и у одной задачи может быть несколько экземпляров (но только если операция в верхней части заднего стека не является существующим экземпляром действия). Например, предположим, что задний стек задачи состоит из корневого действия A с действиями B, C и D сверху (стек ABCD; D сверху). Намерение приходит для действия типа D. Если D имеет стандартный стандартный режим запуска, запускается новый экземпляр класса, и стек становится ABCDD. Однако, если режим запуска D - "singleTop", существующий экземпляр D получает намерение через onNewIntent(), потому что он находится на вершине стека - стек остается ABCD. Однако, если для действия типа B прибывает намерение, то в стек добавляется новый экземпляр B, даже если его режим запуска "singleTop".

Примечание. Когда создается новый экземпляр действия, пользователь может нажать кнопку "Назад", чтобы вернуться к предыдущему действию. Но когда существующий экземпляр действия обрабатывает новое намерение, пользователь не может нажать кнопку "Назад", чтобы вернуться в состояние действия, пока новое намерение не поступило в onNewIntent().

Вы должны прочитать документацию здесь для получения дополнительной информации по теме

Другие вопросы по тегам