支持FragmentPagerAdapter保存对旧片段的引用

时间:2012-03-15 19:54:47

标签: android android-fragments

最新信息:

我已经将我的问题缩小到了一个问题,片段管理器保留了旧片段的实例,而我的viewpager与我的FragmentManager不同步。请参阅此问题... http://code.google.com/p/android/issues/detail?id=19211#makechanges。我仍然不知道如何解决这个问题。任何建议......

我已经尝试了很长时间的调试,非常感谢任何帮助。我正在使用FragmentPagerAdapter,它接受像这样的片段列表:

List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName())); 
...
new PagerAdapter(getSupportFragmentManager(), fragments);

实施是标准的。我正在为Fragments使用ActionBarSherlock和v4可计算性库。

我的问题是,在离开应用程序并打开其他几个应用程序并返回后,片段将丢失其对FragmentActivity的引用(即getActivity() == null)。我无法弄清楚为什么会这样。我试图手动设置setRetainInstance(true);,但这没有帮助。我想当我的FragmentActivity被破坏时会发生这种情况,但是如果我在收到日志消息之前打开应用程序,这仍然会发生。有什么想法吗?

@Override
protected void onDestroy(){
    Log.w(TAG, "DESTROYDESTROYDESTROYDESTROYDESTROYDESTROYDESTROY");
    super.onDestroy();
}

适配器:

public class PagerAdapter extends FragmentPagerAdapter {
    private List<Fragment> fragments;

    public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);

        this.fragments = fragments;

    }

    @Override
    public Fragment getItem(int position) {

        return this.fragments.get(position);

    }

    @Override
    public int getCount() {

        return this.fragments.size();

    }

}

我的一个碎片被剥夺了但是我很满意每一个被剥离但仍然无法工作......

public class MyFragment extends Fragment implements MyFragmentInterface, OnScrollListener {
...

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    handler = new Handler();    
    setHasOptionsMenu(true);
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    Log.w(TAG,"ATTACHATTACHATTACHATTACHATTACH");
    context = activity;
    if(context== null){
        Log.e("IS NULL", "NULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULL");
    }else{
        Log.d("IS NOT NULL", "NOTNOTNOTNOTNOTNOTNOTNOT");
    }

}

@Override
public void onActivityCreated(Bundle savedState) {
    super.onActivityCreated(savedState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.my_fragment,container, false);

    return v;
}


@Override
public void onResume(){
    super.onResume();
}

private void callService(){
    // do not call another service is already running
    if(startLoad || !canSet) return;
    // set flag
    startLoad = true;
    canSet = false;
    // show the bottom spinner
    addFooter();
    Intent intent = new Intent(context, MyService.class);
    intent.putExtra(MyService.STATUS_RECEIVER, resultReceiver);
    context.startService(intent);
}

private ResultReceiver resultReceiver = new ResultReceiver(null) {
    @Override
    protected void onReceiveResult(int resultCode, final Bundle resultData) {
        boolean isSet = false;
        if(resultData!=null)
        if(resultData.containsKey(MyService.STATUS_FINISHED_GET)){
            if(resultData.getBoolean(MyService.STATUS_FINISHED_GET)){
                removeFooter();
                startLoad = false;
                isSet = true;
            }
        }

        switch(resultCode){
        case MyService.STATUS_FINISHED: 
            stopSpinning();
            break;
        case SyncService.STATUS_RUNNING:
            break;
        case SyncService.STATUS_ERROR:
            break;
        }
    }
};

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.clear();
    inflater.inflate(R.menu.activity, menu);
}

@Override
public void onPause(){
    super.onPause();
}

public void onScroll(AbsListView arg0, int firstVisible, int visibleCount, int totalCount) {
    boolean loadMore = /* maybe add a padding */
        firstVisible + visibleCount >= totalCount;

    boolean away = firstVisible+ visibleCount <= totalCount - visibleCount;

    if(away){
        // startLoad can now be set again
        canSet = true;
    }

    if(loadMore) 

}

public void onScrollStateChanged(AbsListView arg0, int state) {
    switch(state){
    case OnScrollListener.SCROLL_STATE_FLING: 
        adapter.setLoad(false); 
        lastState = OnScrollListener.SCROLL_STATE_FLING;
        break;
    case OnScrollListener.SCROLL_STATE_IDLE: 
        adapter.setLoad(true);
        if(lastState == SCROLL_STATE_FLING){
            // load the images on screen
        }

        lastState = OnScrollListener.SCROLL_STATE_IDLE;
        break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        adapter.setLoad(true);
        if(lastState == SCROLL_STATE_FLING){
            // load the images on screen
        }

        lastState = OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;
        break;
    }
}

@Override
public void onDetach(){
    super.onDetach();
    if(this.adapter!=null)
        this.adapter.clearContext();

    Log.w(TAG, "DETACHEDDETACHEDDETACHEDDETACHEDDETACHEDDETACHED");
}

public void update(final int id, String name) {
    if(name!=null){
        getActivity().getSupportActionBar().setTitle(name);
    }

}

}

当用户与不同的片段交互并且getActivity返回null时,将调用update方法。这是另一个片段正在调用的方法......

((MyFragment) pagerAdapter.getItem(1)).update(id, name);

我相信当应用程序被销毁然后再次创建而不是仅启动应用程序到应用程序启动的默认片段,然后viewpager导航到最后一个已知页面。这看起来很奇怪,不应该只是加载到默认片段的应用程序?

13 个答案:

答案 0 :(得分:118)

您遇到了问题,因为您正在实例化并保留对PagerAdapter.getItem之外的片段的引用,并且正在尝试独立于ViewPager使用这些引用。正如Seraph所说,你确实保证在特定时间在ViewPager中实例化/添加了一个片段 - 这应该被视为一个实现细节。 ViewPager会对其页面进行延迟加载;默认情况下,它只加载当前页面,左侧和右侧加载。

如果您将应用程序置于后台,则会自动保存已添加到片段管理器中的片段。即使您的应用被杀,重新启动应用时也会恢复此信息。

现在考虑您已经查看了几个页面,片段A,B和C.您知道这些已添加到片段管理器中。因为您使用的是FragmentPagerAdapter而不是FragmentStatePagerAdapter,所以当您滚动到其他页面时,这些片段仍会被添加(但可能会分离)。

考虑一下你的应用程序后台,然后它就会被杀死。当你回来时,Android会记住你曾经在片段管理器中有片段A,B和C,因此它会为你重新创建它们然后添加它们。 但是,现在添加到片段管理器中的那些不是您的活动中片段列表中的那些。

如果已经为该特定页面位置添加了片段,FragmentPagerAdapter将不会尝试调用getPosition。实际上,由于Android重新创建的片段永远不会被删除,因此您无需通过调用getPosition来替换它。获取对它的处理也非常困难,因为它添加了一个您不知道的标记。这是设计的;你不鼓励搞乱视图寻呼机管理的片段。您应该在片段中执行所有操作,与活动通信,并在必要时请求切换到特定页面。

现在,回到你缺少活动的问题。在所有这些事件发生之后调用pagerAdapter.getItem(1)).update(id, name)会返回列表中的片段,尚未添加到片段管理器,因此它不会有Activity引用。我建议您的更新方法应该修改一些共享数据结构(可能由活动管理),然后当您移动到特定页面时,它可以根据此更新数据绘制自己。

答案 1 :(得分:104)

我找到了对我有用的简单解决方案。

使您的片段适配器扩展FragmentStatePagerAdapter而不是FragmentPagerAdapter并覆盖onSave方法以返回null

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

这可以防止android重新创建片段


一天后,我找到了另一个更好的解决方案。

为所有片段调用setRetainInstance(true)并在某处保存对它们的引用。我在我的活动中使用静态变量做了那个,因为它被声明为singleTask并且片段可以一直保持不变。

这样android不会重新创建片段,而是使用相同的实例。

答案 2 :(得分:27)

我通过FragmentManager直接访问我的片段而不是像FragmentPagerAdapter那样解决了这个问题。首先,我需要找出FragmentPagerAdapter自动生成的片段的标签...

private String getFragmentTag(int pos){
    return "android:switcher:"+R.id.viewpager+":"+pos;
}

然后我只是得到一个对该片段的引用并做我需要的事情......

Fragment f = this.getSupportFragmentManager().findFragmentByTag(getFragmentTag(1));
((MyFragmentInterface) f).update(id, name);
viewPager.setCurrentItem(1, true);

在我的片段中,我设置setRetainInstance(false);,以便我可以手动将值添加到savedInstanceState包中。

@Override
public void onSaveInstanceState(Bundle outState) {
    if(this.my !=null)
        outState.putInt("myId", this.my.getId());

    super.onSaveInstanceState(outState);
}

然后在OnCreate中我抓住该密钥并根据需要恢复片段的状态。一个简单的解决方案,对我来说很难(至少对我而言)。

答案 3 :(得分:22)

全球工作测试解决方案。

getSupportFragmentManager()保留空引用一些次,View寻呼机不会创建新的,因为它找到对同一片段的引用。所以过度使用getChildFragmentManager()以简单的方式解决问题。

不要这样做:

<强> new PagerAdapter(getSupportFragmentManager(), fragments);

执行此操作:

<强> new PagerAdapter(getChildFragmentManager() , fragments);

答案 4 :(得分:7)

不要尝试在ViewPager中的片段之间进行交互。您不能保证附加或甚至存在其他片段。无需从片段更改操作栏标题,您可以从您的活动中执行此操作。使用标准接口模式:

public interface UpdateCallback
{
    void update(String name);
}

public class MyActivity extends FragmentActivity implements UpdateCallback
{
    @Override
    public void update(String name)
    {
        getSupportActionBar().setTitle(name);
    }

}

public class MyFragment extends Fragment
{
    private UpdateCallback callback;

    @Override
    public void onAttach(SupportActivity activity)
    {
        super.onAttach(activity);
        callback = (UpdateCallback) activity;
    }

    @Override
    public void onDetach()
    {
        super.onDetach();
        callback = null;
    }

    public void updateActionbar(String name)
    {
        if(callback != null)
            callback.update(name);
    }
}

答案 5 :(得分:4)

在寻找类似问题几个小时后,我认为还有另一个解决方案。这个至少它对我有用,我只需改变几行。

这是我遇到的问题,我有一个带有视图寻呼机的活动,它使用带有两个片段的FragmentStatePagerAdapter。一切正常,直到我强制活动被销毁(开发者选项)或我旋转屏幕。在方法getItem中创建后,我确实会对这两个片段进行引用。

此时活动将再次创建,此时一切正常但我丢失了对我的fragmetns的引用,因为getItem没有&#39;#再次被召唤。

这就是我在FragmentStatePagerAdapter中解决这个问题的方法:

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Object aux = super.instantiateItem(container, position);

        //Update the references to the Fragments we have on the view pager
        if(position==0){
            fragTabOne = (FragOffersList)aux;
        }
        else{
            fragTabTwo = (FragOffersList) aux;
        }

        return aux;
    }

如果适配器内部已经引用了getItem,那么你不会再次调用getItem,而且你不应该改变它。相反,您可以通过查看将为每个片段调用的另一个方法instantiateItem()来获取正在使用的片段。

希望能帮助任何人。

答案 6 :(得分:4)

你可以在销毁viewpager时删除片段,在我的例子中,我在片段的onDestroyView()上删除了它们:

@Override
public void onDestroyView() {

    if (getChildFragmentManager().getFragments() != null) {
        for (Fragment fragment : getChildFragmentManager().getFragments()) {
            getChildFragmentManager().beginTransaction().remove(fragment).commitAllowingStateLoss();
        }
    }

    super.onDestroyView();
}

答案 7 :(得分:0)

由于FragmentManager将在调用onResume()方法后立即为您恢复片段,因此我将片段调用到活动并将其自身添加到列表中。在我的实例中,我将所有这些存储在我的PagerAdapter实现中。每个片段都知道它的位置,因为它在创建时被添加到片段参数中。现在每当我需要在特定索引处操作片段时,我所要做的就是使用我的适配器中的列表。

以下是自定义ViewPager的适配器示例,它将在片段移动到焦点时生长片段,并在片段移出焦点时缩小片段。除了我在这里所需的Adapter和Fragment类,所有你需要的是父活动能够引用适配器变量并且你已经设置了。

<强>适配器

public class GrowPagerAdapter extends FragmentPagerAdapter implements OnPageChangeListener, OnScrollChangedListener {

public final String TAG = this.getClass().getSimpleName();

private final int COUNT = 4;

public static final float BASE_SIZE = 0.8f;
public static final float BASE_ALPHA = 0.8f;

private int mCurrentPage = 0;
private boolean mScrollingLeft;

private List<SummaryTabletFragment> mFragments;

public int getCurrentPage() {
    return mCurrentPage;
}

public void addFragment(SummaryTabletFragment fragment) {
    mFragments.add(fragment.getPosition(), fragment);
}

public GrowPagerAdapter(FragmentManager fm) {
    super(fm);

    mFragments = new ArrayList<SummaryTabletFragment>();
}

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

@Override
public Fragment getItem(int position) {
    return SummaryTabletFragment.newInstance(position);
}

@Override
public void onPageScrollStateChanged(int state) {}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    adjustSize(position, positionOffset);
}

@Override
public void onPageSelected(int position) {
    mCurrentPage = position;
}

/**
 * Used to adjust the size of each view in the viewpager as the user
 * scrolls.  This provides the effect of children scaling down as they
 * are moved out and back to full size as they come into focus.
 * 
 * @param position
 * @param percent
 */
private void adjustSize(int position, float percent) {

    position += (mScrollingLeft ? 1 : 0);
    int secondary = position + (mScrollingLeft ? -1 : 1);
    int tertiary = position + (mScrollingLeft ? 1 : -1);

    float scaleUp = mScrollingLeft ? percent : 1.0f - percent;
    float scaleDown = mScrollingLeft ? 1.0f - percent : percent;

    float percentOut = scaleUp > BASE_ALPHA ? BASE_ALPHA : scaleUp;
    float percentIn = scaleDown > BASE_ALPHA ? BASE_ALPHA : scaleDown;

    if (scaleUp < BASE_SIZE)
        scaleUp = BASE_SIZE;

    if (scaleDown < BASE_SIZE)
        scaleDown = BASE_SIZE;

    // Adjust the fragments that are, or will be, on screen
    SummaryTabletFragment current = (position < mFragments.size()) ? mFragments.get(position) : null;
    SummaryTabletFragment next = (secondary < mFragments.size() && secondary > -1) ? mFragments.get(secondary) : null;
    SummaryTabletFragment afterNext = (tertiary < mFragments.size() && tertiary > -1) ? mFragments.get(tertiary) : null;

    if (current != null && next != null) {

        // Apply the adjustments to each fragment
        current.transitionFragment(percentIn, scaleUp);
        next.transitionFragment(percentOut, scaleDown);

        if (afterNext != null) {
            afterNext.transitionFragment(BASE_ALPHA, BASE_SIZE);
        }
    }
}

@Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {

    // Keep track of which direction we are scrolling
    mScrollingLeft = (oldl - l) < 0;
}
}

<强>片段

public class SummaryTabletFragment extends BaseTabletFragment {

public final String TAG = this.getClass().getSimpleName();

private final float SCALE_SIZE = 0.8f;

private RelativeLayout mBackground, mCover;
private TextView mTitle;
private VerticalTextView mLeft, mRight;

private String mTitleText;
private Integer mColor;

private boolean mInit = false;
private Float mScale, mPercent;

private GrowPagerAdapter mAdapter;
private int mCurrentPosition = 0;

public String getTitleText() {
    return mTitleText;
}

public void setTitleText(String titleText) {
    this.mTitleText = titleText;
}

public static SummaryTabletFragment newInstance(int position) {

    SummaryTabletFragment fragment = new SummaryTabletFragment();
    fragment.setRetainInstance(true);

    Bundle args = new Bundle();
    args.putInt("position", position);
    fragment.setArguments(args);

    return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);

    mRoot = inflater.inflate(R.layout.tablet_dummy_view, null);

    setupViews();
    configureView();

    return mRoot;
}

@Override
public void onViewStateRestored(Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);

    if (savedInstanceState != null) {
        mColor = savedInstanceState.getInt("color", Color.BLACK);
    }

    configureView();
}

@Override
public void onSaveInstanceState(Bundle outState)  {

    outState.putInt("color", mColor);

    super.onSaveInstanceState(outState);
}

@Override
public int getPosition() {
    return getArguments().getInt("position", -1);
}

@Override
public void setPosition(int position) {
    getArguments().putInt("position", position);
}

public void onResume() {
    super.onResume();

    mAdapter = mActivity.getPagerAdapter();
    mAdapter.addFragment(this);
    mCurrentPosition = mAdapter.getCurrentPage();

    if ((getPosition() == (mCurrentPosition + 1) || getPosition() == (mCurrentPosition - 1)) && !mInit) {
        mInit = true;
        transitionFragment(GrowPagerAdapter.BASE_ALPHA, GrowPagerAdapter.BASE_SIZE);
        return;
    }

    if (getPosition() == mCurrentPosition && !mInit) {
        mInit = true;
        transitionFragment(0.00f, 1.0f);
    }
}

private void setupViews() {

    mCover = (RelativeLayout) mRoot.findViewById(R.id.cover);
    mLeft = (VerticalTextView) mRoot.findViewById(R.id.title_left);
    mRight = (VerticalTextView) mRoot.findViewById(R.id.title_right);
    mBackground = (RelativeLayout) mRoot.findViewById(R.id.root);
    mTitle = (TextView) mRoot.findViewById(R.id.title);
}

private void configureView() {

    Fonts.applyPrimaryBoldFont(mLeft, 15);
    Fonts.applyPrimaryBoldFont(mRight, 15);

    float[] size = UiUtils.getScreenMeasurements(mActivity);
    int width = (int) (size[0] * SCALE_SIZE);
    int height = (int) (size[1] * SCALE_SIZE);

    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);
    mBackground.setLayoutParams(params);

    if (mScale != null)
        transitionFragment(mPercent, mScale);

    setRandomBackground();

    setTitleText("Fragment " + getPosition());

    mTitle.setText(getTitleText().toUpperCase());
    mLeft.setText(getTitleText().toUpperCase());
    mRight.setText(getTitleText().toUpperCase());

    mLeft.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            mActivity.showNextPage();
        }
    });

    mRight.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            mActivity.showPrevPage();
        }
    });
}

private void setRandomBackground() {

    if (mColor == null) {
        Random r = new Random();
        mColor = Color.rgb(r.nextInt(255), r.nextInt(255), r.nextInt(255));
    }

    mBackground.setBackgroundColor(mColor);
}

public void transitionFragment(float percent, float scale) {

    this.mScale = scale;
    this.mPercent = percent;

    if (getView() != null && mCover != null) {

        getView().setScaleX(scale);
        getView().setScaleY(scale);

        mCover.setAlpha(percent);
        mCover.setVisibility((percent <= 0.05f) ? View.GONE : View.VISIBLE);
    }
}

@Override
public String getFragmentTitle() {
    return null;
}
}

答案 8 :(得分:0)

我的解决方案:我几乎将每个视图设置为static。现在我的应用程序交互完美。能够从任何地方调用静态方法可能不是一个好的风格,但为什么要使用不起作用的代码呢?我在这里阅读了很多问题及其答案,没有解决方案带来成功(对我而言)。

我知道它可以泄漏内存,浪费堆,我的代码也不适合其他项目,但我不会对此感到害怕 - 我在不同的设备和条件下测试了应用程序,没有问题根本没有,Android平台似乎能够处理这个问题。 UI每秒刷新一次,即使在S2 ICS(4.0.3)设备上,该应用程序也能够处理数千个地理标记。

答案 9 :(得分:0)

我遇到了同样的问题,但我的ViewPager在TopFragment中,使用setAdapter(new FragmentPagerAdapter(getChildFragmentManager()))创建并设置了适配器。

我通过覆盖TopFragment中的onAttachFragment(Fragment childFragment)来修复此问题,如下所示:

@Override
public void onAttachFragment(Fragment childFragment) {
    if (childFragment instanceof OnboardingDiamondsFragment) {
        mChildFragment = (ChildFragment) childFragment;
    }

    super.onAttachFragment(childFragment);
}

如已知的那样(参见上面的答案),当childFragmentManager重新创建自身时,它还会创建viewPager中的片段。
重要的是,在那之后,他调用 onAttachFragment ,现在我们引用了新重建的片段!

希望这会帮助任何人像我一样得到这个老Q:)

答案 10 :(得分:0)

我通过在SparceArray中保存片段解决了这个问题:

public abstract class SaveFragmentsPagerAdapter extends FragmentPagerAdapter {

    SparseArray<Fragment> fragments = new SparseArray<>();

    public SaveFragmentsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        fragments.append(position, fragment);
        return fragment;
    }

    @Nullable
    public Fragment getFragmentByPosition(int position){
        return fragments.get(position);
    }

}

答案 11 :(得分:0)

只是你知道......

通过这些类添加一连串的困境,有一个值得分享的相当有趣的错误。

我正在使用ViewPager导航项目树(选择一个项目,视图寻呼机动画向右滚动,下一个分支出现,向后导航,ViewPager向相反方向滚动返回到上一节点。)

当我从FragmentStatePagerAdapter的末尾推送和弹出片段时出现问题。它足够聪明,可以注意到项目发生了变化,并且足够聪明,可以在项目发生变化时创建和替换片段。但是不够聪明以丢弃片段状态,或者足够智能以在适配器大小改变时修剪内部保存的片段状态。因此,当您弹出一个项目并将一个新项目推送到最后时,新项目的片段将获得旧项目的片段的已保存状态,这会在我的代码中造成严重破坏。我的片段带有可能需要大量工作才能从互联网上重新获取的数据,所以不能保存状态真的不是一种选择。

我没有干净的解决方法。我使用过这样的东西:

  public void onSaveInstanceState(Bundle outState) {
    IFragmentListener listener = (IFragmentListener)getActivity();
    if (listener!= null)
    {
        if (!listener.isStillInTheAdapter(this.getAdapterItem()))
        {
            return; // return empty state.
        }

    }
    super.onSaveInstanceState(outState);

    // normal saving of state for flips and 
    // paging out of the activity follows
    ....
  }

一个不完美的解决方案,因为新的片段实例仍然会获得savedState Bundle,但至少它不会携带过时的数据。

答案 12 :(得分:0)

由于人们不喜欢阅读评论,因此这里给出的答案大部分与我写的here相同:

此问题的根本原因是android系统不会调用getItem来获取实际显示的片段,而是调用instantiateItem。此方法首先尝试为FragmentManager中的给定选项卡查找和重用片段实例。仅当此查找失败(仅在第一次创建FragmentManager时才发生)时,才会调用getItem。出于明显的原因,例如,每次用户旋转设备时,都不要重新创建碎片(可能很重)。
为了解决这个问题,不要在活动中使用Fragment.instantiate创建片段,而应使用pagerAdapter.instantiateItem来完成所有这些调用,而所有这些调用都应由分别启动/提交片段事务的startUpdate/finishUpdate方法调用包围。 getItem应该是使用各自的构造函数真正创建片段的地方。

List<Fragment> fragments = new Vector<Fragment>();

@Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.myLayout);
        ViewPager viewPager = (ViewPager) findViewById(R.id.myViewPager);
        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);
        ((TabLayout) findViewById(R.id.tabs)).setupWithViewPager(viewPager);

        adapter.startUpdate(viewPager);
        fragments.add(adapter.instantiateItem(viewPager, 0));
        fragments.add(adapter.instantiateItem(viewPager, 1));
        // and so on if you have more tabs...
        adapter.finishUpdate(viewPager);
}

class MyPagerAdapter extends FragmentPagerAdapter {

        public MyPagerAdapter(FragmentManager manager) {super(manager);}

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

        @Override public Fragment getItem(int position) {
            if (position == 0) return new Fragment0();
            if (position == 1) return new Fragment1();
            return null;  // or throw some exception
        }

        @Override public CharSequence getPageTitle(int position) {
            if (position == 0) return getString(R.string.tab0);
            if (position == 1) return getString(R.string.tab1);
            return null;  // or throw some exception
        }
}