Android FragmentTab主机和片段内的片段

时间:2013-03-11 22:22:47

标签: android android-fragments xamarin.android android-tabhost android-nested-fragment

我有一个像这样的层次结构的应用程序:

FragmentTabHost (Main Activity)
  - Fragment (tab 1 content - splitter view)
    - Fragment (lhs, list)
    - Framment (rhs, content view)
  - Fragment (tab 2 content)
  - Fragment (tab 2 content)

所有片段视图都是从资源中膨胀的。

当应用程序启动时,一切都会显示并且看起来很好当我从第一个标签切换到另一个标签然后再返回时,我会尝试通过重新设置标签1的视图来充气。

深入挖掘,这就是发生的事情:

  • 在第一次加载时,对分割器视图进行膨胀会导致其两个子片段被添加到片段管理器中。
  • 在离开第一个标签时,它的视图被破坏,但它的子片段留在片段管理器中
  • 在切换回第一个选项卡时,视图会重新膨胀,并且由于旧的子片段仍在片段管理器中,因此在实例化新的子片段时(通过膨胀)会抛出异常

我通过从片段管理器中删除子片段来解决这个问题(我使用Mono),现在我可以切换标签而没有例外。

public override void OnDestroyView()
{
    var ft = FragmentManager.BeginTransaction();
    ft.Remove(FragmentManager.FindFragmentById(Resource.Id.ListFragment));
    ft.Remove(FragmentManager.FindFragmentById(Resource.Id.ContentFragment));
    ft.Commit();

    base.OnDestroyView();
}

所以我有几个问题:

  1. 以上是正确的方法吗?
  2. 如果没有,我应该怎么做?
  3. 无论哪种方式,保存实例状态如何与所有这些相关联,以便在切换标签时不会丢失视图状态?

2 个答案:

答案 0 :(得分:3)

我不确定如何在Mono中执行此操作,但是要将子片段添加到另一个片段,您无法使用FragmentManager的{​​{1}}。相反,您必须使用托管Activity的{​​{1}}:

http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager() http://developer.android.com/reference/android/support/v4/app/Fragment.html#getChildFragmentManager()

ChildFragmentManager的主Fragment处理您的标签 FragmentManager的{​​{1}}处理拆分视图。

答案 1 :(得分:2)

好的,我终于明白了:

如上所述,首先我将片段创建更改为以编程方式完成,并将它们添加到子片段管理器中,如下所示:

public override View OnCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstance)
{
    var view = inflater.Inflate(Resource.Layout.MyView, viewGroup, false);

    // Add fragments to the child fragment manager
    // DONT DO THIS, SEE BELOW 
    var tx = ChildFragmentManager.BeginTransaction();
    tx.Add(Resource.Id.lhs_fragment_frame, new LhsFragment());
    tx.Add(Resource.Id.rhs_fragment_frame, new RhsFragment());
    tx.Commit();

    return view;
}

正如所料,每次切换标签时,都会创建一个额外的Lhs / RhsFragment实例,但我注意到旧的Lhs / RhsFragment的OnCreateView也会被调用。因此,在每个选项卡切换后,将再次调用OnCreateView。切换标签10次= 11次调用OnCreateView。这显然是错误的。

查看FragmentTabHost的源代码,我可以看到它只是在切换选项卡时分离并重新附加选项卡的内容片段。似乎父Fragment的ChildFragmentManager正在保留子片段并在重新附加父片段时自动重新创建它们的视图。

所以,我将片段的创建移动到OnCreate,并且只有当我们没有从保存的状态加载时才会这样做:

public override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    if (savedInstanceState == null)
    {
        var tx = ChildFragmentManager.BeginTransaction();
        tx.Add(Resource.Id.lhs_fragment_frame, new LhsFragment());
        tx.Add(Resource.Id.rhs_fragment_frame, new RhsFragment());
        tx.Commit();
    }
}


public override View OnCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstance)
{
    // Don't instatiate child fragments here

    return inflater.Inflate(Resource.Layout.MyView, viewGroup, false);
}

这修复了附加视图的创建和切换选项卡现在基本上工作了。

下一个问题是保存和恢复视图状态。在子片段中,我需要保存并恢复当前选定的项目。最初我有这样的东西(这是子片段的OnCreateView)

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance)
{
    var view = inflater.Inflate(Resource.Layout.CentresList, container, false);

    // ... other code ommitted ...

    // DONT DO THIS, SEE BELOW 
    if (savedInstance != null)
    {
        // Restore selection
        _selection = savedInstance.GetString(KEY_SELECTION);
    }
    else
    {
        // Select first item
        _selection =_items[0];  
    }

    return view;
}

问题在于切换标签时标签主机不会调用OnSaveInstanceState。相反,子片段保持活动状态,它的_selection变量可以保持不变。

所以我将代码移动到OnCreate管理选择:

public override void OnCreate(Bundle savedInstance)
{
    base.OnCreate(savedInstance);

    if (savedInstance != null)
    {
        // Restore Selection
        _selection = savedInstance.GetString(BK_SELECTION);
    }
    else
    {
        // Select first item
        _selection = _items[0];
    }
}

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance)
{
    // Don't restore/init _selection here

    return inflater.Inflate(Resource.Layout.CentresList, container, false);
}

现在,当切换标签和改变方向时,这一切看起来都很完美。