Фрагменты Android — несколько вкладок/потоков страниц, настраиваемый задний стек

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

transaction.hide(currentFragment).show(newFragment).commit();

Я думаю, что в моей ситуации поможет временное уничтожение представления фрагмента, а затем его воссоздание, когда фрагмент снова отображается (вместо того, чтобы просто скрывать пользовательский интерфейс от представления пользователя). Из чтения API не похоже, что метод скрытия делает это. Кто-нибудь знает, есть ли какие-то встроенные методы в класс FragmentTransaction/FragmentManager/Fragment, которые позволят мне это сделать?

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

Спасибо, ребята, я ценю вашу помощь в этом.


person abeauchamp    schedule 09.09.2013    source источник


Ответы (1)


Я придумал решение для достижения лучшего решения с управлением памятью (на основе адаптера) для одновременного сохранения нескольких пользовательских поездок (независимые вкладки с чем-то, что представляет собой бэкстеки). Я отказался от использования FragmentManager, так как это не способствовало такому поведению. Я оставлю свой ответ здесь на случай, если кто-то еще столкнется с аналогичной проблемой, связанной с необходимостью этой идеи нескольких бэкстеков с использованием ViewPagers с FragmentStatePagerAdapter - один просмотрщик для каждой вкладки в своем приложении (это все еще можно очистить больше, но вы можете получить jist) :

Основная деятельность:

public class MultiTabbedActivity extends FragmentActivity implements NavigationFragment.OnNavigationSelectedListener
{

    private Page1Fragment mPage1;
    private Page2Fragment mPage2;


    private CustomFragment mCurrent;
    private String mNav;

    private List<CustomFragment> mPage1BackStack;
    private List<CustomFragment> mPage2BackStack;

    private CustomViewPager mPagerPage1;
    private CustomViewPager mPagerPage2;

    private boolean mUpdating = false;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // initialize the backstacks
        mPage1BackStack = new ArrayList<CustomFragment>();
        mPage2BackStack = new ArrayList<CustomFragment>();

        mPage1 = new Page1Fragment();
        mPage2 = new Page2Fragment();

        mPage1BackStack.add(mPage1);
        mPage2BackStack.add(mPage2);

        mPagerPage1 = (CustomViewPager) findViewById(R.id.page1_fragment);
        mPagerPage2 = (CustomViewPager) findViewById(R.id.page2_fragment);

        mPagerPage1.setOffscreenPageLimit(3); //Customizable to determine how many 
        mPagerPage2.setOffscreenPageLimit(3); //fragments you want to hold in memory

        mPagerPage1.setAdapter(new CustomFragmentAdapter(getSupportFragmentManager(), mPage1BackStack));
        mPagerPage2.setAdapter(new CustomFragmentAdapter(getSupportFragmentManager(), mPage2BackStack));

        displayPager(mPagerPage1);
        mCurrent = mPage1;
        mNav = GlobalConstants.PAGE_PAGE1;

    }

    private void displayPager(ViewPager pager)
    {
        mPagerPage1.setVisibility(ViewPager.GONE);
        mPagerPage2.setVisibility(ViewPager.GONE);

        pager.setCurrentItem(pager.getAdapter().getCount() - 1);
        pager.getAdapter().notifyDataSetChanged();
        pager.setVisibility(ViewPager.VISIBLE);
    }

    @Override
    public void onNavSelected(String page)
    {
        if (page != null && page != "" && !mUpdating)
        {
            // Determine the Fragment selected
            if (page.equalsIgnoreCase(GlobalConstants.PAGE_PAGE1))
            {
                mNav = GlobalConstants.PAGE_PAGE1;
                displayPager(mPagerPage1);
                mCurrent = mPage1BackStack.get(mPage1BackStack.size() - 1);
            }
            else if (page.equalsIgnoreCase(GlobalConstants.PAGE_PAGE2))
            {
                mNav = GlobalConstants.PAGE_PAGE2;
                displayPager(mPagerPage2);
                mCurrent = mPage2BackStack.get(mPage2BackStack.size() - 1);
            }
        }
    }


    @Override
    public void onBackPressed()
    {
        PageFragment navFrag = null;
        // Update the Navigation Menu to indicate the currently visible
        // Fragment
        try
        {
            mUpdating = true;

            if (mPage1BackStack.size() > 1 && mNav.equalsIgnoreCase(GlobalConstants.PAGE_PAGE1))
            {
                mPagerPage1.setCurrentItem(mPage1BackStack.size() - 2);
                mPage1BackStack.remove(mPage1BackStack.size() - 1);
                navFrag = mPage1BackStack.get(mPage1BackStack.size() - 1);
                mPagerPage1.setAdapter(new CustomFragmentAdapter(getSupportFragmentManager(), mPage1BackStack));
            }
            else if (mPage2BackStack.size() > 1 && mNav.equalsIgnoreCase(GlobalConstants.PAGE_PAGE2))
            {
                mPagerPage2.setCurrentItem(mPage2BackStack.size() - 2);
                mPage2BackStack.remove(mPage2BackStack.size() - 1);
                navFrag = mPage2BackStack.get(mPage2BackStack.size() - 1);
                mPagerPage2.setAdapter(new CustomFragmentAdapter(getSupportFragmentManager(), mPage2BackStack));
            }
            else
            {
                super.onBackPressed();
            }

            if (navFrag != null)
                mCurrent = navFrag;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            mUpdating = false;
        }
    }

    public void updateFragment(PageFragment newFragment)
    {
        if (mNav.equalsIgnoreCase(GlobalConstants.PAGE_PAGE1))
        {
            mPage1BackStack.add(newFragment);
            displayPager(mPagerPage1);
        }
        else if (mNav.equalsIgnoreCase(GlobalConstants.PAGE_PAGE2))
        {
            mPage2BackStack.add(newFragment);
            displayPager(mPagerPage2);
        }
        mCurrent = newFragment;
    }
}

CustomViewPager:

public class CustomViewPager extends ViewPager {

    private boolean enabled;

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onInterceptTouchEvent(event);
        }

        return false;
    }

    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}

Пользовательский адаптер:

public class CustomFragmentAdapter extends FragmentStatePagerAdapter
{
    List<CustomFragment> mFragments;

    public CustomFragmentAdapter(FragmentManager fm, List<CustomFragment> fragments)
    {
        super(fm);
        mFragments = fragments;
    }

    public List<PageFragment> getmFragments()
    {
        return mFragments;
    }

    public void setmFragments(List<CustomFragment> mFragments)
    {
        this.mFragments = mFragments;
    }

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

    @Override
    public Fragment getItem(int position)
    {
        return (Fragment) (mFragments.get(position));
    }
}

Пользовательский интерфейс (завернутый в линейный макет):

    <fragment
        android:id="@+id/navigation_fragment"
        android:name="your.package.here.NavigationFragment"
        android:layout_width="70dp"
        android:layout_height="match_parent" />

    <FrameLayout
        android:id="@+id/page_fragment"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_weight="2" >

        <your.package.here.CustomViewPager
            android:id="@+id/page1_fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone" />
        <your.package.here.CustomViewPager
            android:id="@+id/page2_fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone" />
    </FrameLayout>
person abeauchamp    schedule 11.09.2013