如何防止 SupportV4 (Fragment)Tabhost 在 TabChange 上创建自己的 Fragment?

How to prevent SupportV4 (Fragment)Tabhost creating its own Fragment at TabChange?

我在 SupportV4 标签主机中的片段有问题,它在单个标签更改期间加载了两个片段。 (使用了 Tabhost;android/support/v4/app/FragmentTabHost)

出现问题是因为我想使用 MVVMCross 及其 ViewModel,所以我需要在片段(位于选项卡内)中加载 ViewModel。

为了解决问题,我使用了以下流程; - 加载 ActionActivity,然后加载 Fragment 以容纳 Tabs - 添加标签(在片段内) - 添加每个 TabChange 开关片段与 SupportFragmentManager

我的包含选项卡的片段具有以下内容:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    var ignored = base.OnCreateView(inflater, container, savedInstanceState);
    var rootView = this.BindingInflate(LayoutId, null);

    activityTabHost = (FragmentTabHost) rootView.FindViewById(Android.Resource.Id.TabHost);
    activityTabHost.Setup(Activity, ChildFragmentManager, Resource.Id.realtabcontent);

    var savedcurrentTabTag = string.Empty;

    AddTabs(savedInstanceState);

    if (savedInstanceState != null) {
        savedcurrentTabTag = savedInstanceState.GetString(SavedTabIndexStateKey);
        activityTabHost.SetCurrentTabByTag(savedcurrentTabTag);
    }

    if (lookup.Any()) {
        OnTabChanged(string.IsNullOrWhiteSpace(savedcurrentTabTag) ? lookup.First().Key : savedcurrentTabTag);
    }

    activityTabHost.SetOnTabChangedListener(this);

    return rootView;
}

TabLoading(一个接一个)

private static void AddTab(Fragment fragment, // Check incomming (was MvxTabsFragmentActivity)
TabHost tabHost,
Android.Widget.TabHost.TabSpec tabSpec,
MvxTabFragmentInfo tabInfo) {
    // Attach a Tab view factory to the spec
    tabSpec.SetContent(new MvxTabFragmentFactory(fragment.Activity));
    var tag = tabSpec.Tag;

    // Check to see if we already have a CachedFragment for this tab, probably
    // from a previously saved state.  If so, deactivate it, because our
    // initial state is that a tab isn't shown.
    tabInfo.CachedFragment = fragment.ChildFragmentManager.FindFragmentByTag(tag);
    if (tabInfo.CachedFragment != null && !tabInfo.CachedFragment.IsDetached) {
        var ft = fragment.ChildFragmentManager.BeginTransaction();
        ft.Detach(tabInfo.CachedFragment);
        ft.Commit();
        fragment.ChildFragmentManager.ExecutePendingTransactions();
    }

    tabHost.AddTab(tabSpec, Class.FromType(tabInfo.FragmentType), tabInfo.Bundle);
}

标签更改:

public virtual void OnTabChanged(string tag) {
    var newTab = lookup[tag];
    if (currentTab != newTab) {
        var ft = ChildFragmentManager.BeginTransaction();
        OnTabFragmentChanging(tag, ft);
        if (currentTab != null) {
            if (currentTab.CachedFragment != null) {
                ft.Detach(currentTab.CachedFragment);
            }
        }

        if (newTab != null) {
            if (newTab.CachedFragment == null) {
                // CAUTION!!!
                // This adds a NEW fragment to the ChildFragmentManager, but the TabHost creates its own Fragment to! 
                // (that one needs to be cancled, regocnized by the lack of a ViewModel)
                newTab.CachedFragment = Instantiate(Activity, FragmentJavaName(newTab.FragmentType), newTab.Bundle);
                FixupDataContext(newTab);
                ft.Add(TabContentId, newTab.CachedFragment, newTab.Tag);
            } else {
                FixupDataContext(newTab);
                ft.Attach(newTab.CachedFragment);
            }
        }

        currentTab = newTab;
        currentTabTag = (newTab != null) ? newTab.Tag : string.Empty;
        ft.Commit();
        ChildFragmentManager.ExecutePendingTransactions();
    }

    TabHost.ViewTreeObserver.RemoveOnTouchModeChangeListener(TabHost);
}

如您所见,我目前正在加载自己的 Fragment,然后将 ViewModel 附加到 Fragment。很高兴地说 ViewModel 已经存在,它来自包含 4 个 ViewModel 的父 ViewModel,每个 Tab 一个。

但是! TabHost 在 TabChange 期间创建自己的片段,但没有 ViewModel,因为它不会自动加载到该 MvxFragment 中。

这是我的解决方法,取消没有 ViewModel 的 Fragment (否则我会在彼此之上获得碎片)。

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (ViewModel == null) {
        return null;
    }

    base.OnCreateView(inflater, container, savedInstanceState);
    return this.BindingInflate(Resource.Layout.GroupedFragmentView, null);
}

这是一个解决方法,我想更好地控制创建片段的 Tabhost。

有谁知道如何进入 SupportV4 tabhost 来控制 Fragment 的创建?或者除了我的解决方法之外还有其他人有好的解决方案吗?

答案是解决方法; (但更好的解决方案是 Cheesebaron 的建议)

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    if (ViewModel == null)
    {
        return null;
    }

    base.OnCreateView(inflater, container, savedInstanceState);
    return this.BindingInflate(Resource.Layout.GroupedFragmentView, null);
}