Android片段 - 多个标签/页面流,自定义后台

时间:2013-09-09 19:08:53

标签: android android-fragments fragmenttransaction fragmentmanager

我遇到了片段的内存问题,我可以使用一些帮助来获取适当的路径。我不能使用简单的backstack,因为应用程序需要保留用户在应用程序中使用的多个路径(并且用户可以来回跳转)。导航以这种方式处理片段:

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

我认为这有助于我的情况是暂时销毁片段的视图,然后在片段放回视图时重新创建(而不是简单地从用户的视图中隐藏UI)。从阅读API,它听起来不像hide方法这样做。有没有人知道FragmentTransaction / FragmentManager / Fragment类是否有一些内置方法可以让我这样做?

我正在考虑的另一个选择是为每个片段创建自己的生命周期。我也探索过使用tabhost,但它似乎没有解决内存问题。如果你有另一个想法,我愿意接受它。

谢谢大家,感谢您对此的帮助。

1 个答案:

答案 0 :(得分:0)

我想出了一个解决方案来实现更好的内存管理解决方案(基于适配器),同时保存多个用户旅程(独立选项卡包含代表backstack的东西)。我使用FragmentManager报废,因为它不利于这种行为。我将在这里留下我的答案以防万一其他人遇到类似的问题,需要使用带有FragmentStatePagerAdapter的ViewPagers的多个反向堆栈 - 一个viewpager用于他们应用程序中的每个选项卡(这仍然可以清理更多,但你可以获得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;
    }
}

CustomAdapter:

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

UI(包裹在线性布局中):

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