ViewPager + Fragment + savedInstanceState

Posted

技术标签:

【中文标题】ViewPager + Fragment + savedInstanceState【英文标题】:ViewPager + Fragment + saveInstanceState 【发布时间】:2014-03-03 14:49:32 【问题描述】:

我有一个包含 ViewPager 的简单 Activity,它显示 Fragments。

我的 Activity 应该显示有关足球联赛的信息,并且每个片段都显示诸如 livescroes/matchdays、table 等信息。

我启动 Activity 时使用的 Intent,包含联赛 ID。

并且每个 Fragment 都需要这个联赛 id 来加载正确的数据。

所以我的 FragmentPagerAdapter 看起来像这样

public class LeaguePagerAdapter extends FragmentPagerAdapter 

    private String leagueId;

    public LeaguePagerAdapter(FragmentManager fm, String leagueId) 
        super(fm);
        this.leagueId = leagueId;
    

    @Override
    public Fragment getItem(int pos) 
        if (pos == 0)
            return TableFragment.newInstance(leagueId);
         else          
            return MatchdayFragment.newInstance(leagueId);
        
    

TableFragment 看起来像这样(比赛日片段看起来很相似):

public class TableFragment extends PullToRefreshListViewAdFragment 

    private String leagueId;

    public static TableFragment newInstance(String leagueId) 
        TableFragment t = new TableFragment();
        t.leagueId = leagueId;
        return t;
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
              // Setup UI and load data
        

有时 LeagueId 为空。我在崩溃日志中看到了异常(crittercism)。但我问自己为什么。在我看来,问题在于活动在后台被破坏并在(例如)用户使用多任务按钮切换到我的应用程序时重建。

据我所知,如果 Activity 已被销毁,原始 Intent 将由 android 自身存储在内部。因此,我没有在我的活动和片段中实现任何 onSaveInstanceState() 。在我的活动中,我阅读了 Intent Extra 以检索leagueId。这工作正常,也可以恢复活动。我假设通过重新创建活动,将创建一个新的 LeaguePagerAdapter,并且所有片段也将被新创建。

正确吗?还是“旧”片段实例将被恢复,因此 LeagueId 为空(因为片段没有将 LeagueId 存储在 Fragments 的 onSaveInstanceState 方法中?)。

有没有办法测试这种生命周期的东西

【问题讨论】:

【参考方案1】:

之所以为null,是因为系统使用默认构造函数恢复Fragment。文件是这样说的:

每个片段都必须有一个空的构造函数,因此可以在恢复其活动状态时对其进行实例化。强烈建议子类不要有其他带参数的构造函数,因为片段重新实例化时不会调用这些构造函数;相反,参数可以由调用者使用 setArguments(Bundle) 提供,然后由 Fragment 使用 getArguments() 检索。

编辑:另外,看看这个:Fragment's onSaveInstanceState() is never called

编辑:为了进一步添加,您正在使用 newInstance(String) 方法创建片段。如果您的 Fragment 被 Android 杀死,它会使用默认构造函数,因此不会设置您的 leagueId 变量。尝试使用 setArguments/getArguments 将值传递到您的 Fragment 中。

【讨论】:

所以我的假设,一个完整的新片段将被实例化是错误的?而 setArguments() 设置的 Arguments 会通过销毁 Fragment 自动保存? @sockeqwe 如果您使用setArguments 而不是像您那样直接进行字段操作,那么据我所知(从我看到的其他答案),系统将在重新创建您的片段时再次使用这些相同的参数.现在的问题是您使用newInstance 实例化您的片段,然后在该方法中设置字段。 Android 在重新创建时不使用newInstance。因此,尝试使用newInstance 内部的setArgumentsleagueId 传递给您的片段,看看是否可行。要进行测试,您可以尝试更改方向或使用 DDMS 终止您的进程。 当然,如果您使用setArguments,那么您必须使用getArguments 检索值。 我将使用 onSaveInstanceState(),因为我可以使用 Annotations 来保存我的值,或者您知道使用 setArguments() 而不是 onSaveInstanceState() 的优点/缺点吗? @sockeqwe 使用 setArguments() 是初始化 Fragment 的正确方法,所以我建议这样做。我建议不要使用onSaveInstanceState(),因为它有不同的目的并且会导致意想不到的副作用。有趣的是,谷歌刚刚在他们的 Google Plus 社区上发布了一篇关于此的帖子:plus.google.com/108967384991768947849/posts/bCD7Zvd945d

以上是关于ViewPager + Fragment + savedInstanceState的主要内容,如果未能解决你的问题,请参考以下文章

在 ViewPager 中用另一个 Fragment 替换一个 Fragment

ViewPager2+Fragment操作笔记

ViewPager2+Fragment操作笔记

ViewPager2+Fragment操作笔记

ViewPager2+Fragment操作笔记

Android 联合ViewPager 与 Fragment