android - 在屏幕旋转时在 ViewPager 中显示带有数据的 fragment

标签 android android-fragments android-viewpager android-lifecycle

因此,在我的 MainActivity OnCreate 中,我创建了 3 个 fragment ,每个 fragment 都填充了不同的数据。然后我将这些 fragment 添加到我的 ViewPagerAdapter。

    ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
    MealsFragment exploreFragment = null;
    MealsFragment favoriteFragment = null;
    MealsFragment localFragment = null;

    //if there is no saved instance, create fragments with passed data as args and add them to the viewpageradapter
    if(savedInstanceState == null){
        exploreFragment = fetchExploreMealsDataAndCreateFragment();
        favoriteFragment = fetchFavoriteMealsDataAndCreateFragment();
        localFragment = fetchLocalMealsDataAndCreateFragment();
    }

    //add fragments to the adapter
    viewPagerAdapter.addFragment(exploreFragment, "EXPLORE");
    viewPagerAdapter.addFragment(favoriteFragment, "FAVORITES");
    viewPagerAdapter.addFragment(localFragment, "LOCAL");

    //set adapter to the viewpager and link it with the different tabs
    mviewPager.setAdapter(viewPagerAdapter);
    mtabLayout.setupWithViewPager(mviewPager);

这 3 种不同的获取方法从 API 或数据库获取数据,所以我不想在每次旋转屏幕和经历我的生命周期时调用这些方法。这就是为什么我首先检查 savedInstanceState 是否为空。但是现在发生的情况是,如果我的 savedInstanceState 不为 null,则 Fragments 将为 null,因为我以这种方式初始化了它们。

显然这不是问题,因为当我旋转屏幕时, fragment 保持不变。我想知道幕后发生了什么,因为我认为这不是处理我的情况的正确方法。也欢迎任何改进建议。

提前致谢!

编辑:

忘了说 ViewPagerAdapter 是我自己实现的 FragmentPageAdapter

public class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragmentList = new ArrayList<>();
private final List<String> fragmentTitleList = new ArrayList<>();

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

@Override
public Fragment getItem(int i) {
    return fragmentList.get(i);
}

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

@Nullable
@Override
public CharSequence getPageTitle(int position) {
    return fragmentTitleList.get(position);
}

public void addFragment(Fragment fragment, String title){
    fragmentList.add(fragment);
    fragmentTitleList.add(title);
}

最佳答案

I was wondering what is going on here behind the scenes

好的,所以,这将涉及查看 FragmentPagerAdapter 的源代码.相关的是 instantiateItem() 的实现方法...虽然实际上只是其中的一部分。

@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
    [...]

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        mCurTransaction.attach(fragment);
    } else {
        fragment = getItem(position);
        if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }

    [...]
}

本质上,getItem()来自你的方法 ViewPagerAdapter在 Activity 的生命周期内,每个位置只调用一次(即使在配置更改时也是如此)。除了第一个,每次都是Fragment直接从 FragmentManager 检索对象与适配器相反。

所以是的,对于您的 Activity 的所有重新创建,您的适配器持有一个 List<Fragment>那只是null , null , null ... 但没关系,因为不会再次访问此列表。

然而

以上陈述假定您的适配器中的每个 fragment 都已构建并添加到 FragmentManager 您的配置更改之前,这是不一定保证的。

默认情况下,ViewPager 的离屏页面限制是1 .这意味着您的第三页(您的 localFragment )不一定添加到 ViewPager 中,因此 FragmentManager , 在首次启动时。如果您滚动到下一页,即使是一次,它也会,但这不一定是真的。

或者您可能手动将屏幕外页面限制设置为 2 ,在这种情况下,将立即添加所有页面/fragment 。


也许最好的办法是改变您使用 FragmentPagerAdapter 的方式共。我会把它放在你的 Activity 里面作为内部类:

private class ExampleAdapter extends FragmentPagerAdapter {

    public ExampleAdapter() {
        super(getSupportFragmentManager());
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0: return fetchExploreMealsDataAndCreateFragment();
            case 1: return fetchFavoriteMealsDataAndCreateFragment();
            case 2: return fetchLocalMealsDataAndCreateFragment();

            default: throw new IllegalArgumentException("unexpected position: " + position);
        }
    }

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
            case 0: return "EXPLORE";
            case 1: return "FAVORITES";
            case 2: return "LOCAL";

            default: throw new IllegalArgumentException("unexpected position: " + position);
        }
    }

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

然后是你的 onCreate()可以改成这样:

FragmentPagerAdapter viewPagerAdapter = new ExampleAdapter();
mviewPager.setAdapter(viewPagerAdapter);
mtabLayout.setupWithViewPager(mviewPager);

这样做的好处是您只需按需调用“获取和创建”方法,但在配置更改后未加载它们的情况下仍然可以在配置更改后调用它们。

关于android - 在屏幕旋转时在 ViewPager 中显示带有数据的 fragment ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52860041/

相关文章:

android - 无法解析方法'add(int, com.example.**.beatle.app.MainActivity.PlaceholderFragment)

Android缩放和旋转 ImageView

android - faSTLane:[!] Google Api 错误:无效请求 - 找不到包:com.example.todo

android - 如何更改Android模拟器临时目录

android - 将 ViewPager 与不带 actionBar 的选项卡一起使用

android - 想在 viewpager 上滑动播放声音

Android:VerticalViewPager 中的垂直 ScrollView 无法正常工作

Samsung Galaxy S4 (SGS4) 上的 Android 套接字问题

android - 启用主页按钮 ActionbarSherlock, Sherlockfragment

android-fragments - 从片段设置半透明状态栏