OK、私は最終的にこれを理解しました:
上で提案したように、最初にフラグメントの作成をプログラムで行うように変更し、次のように子フラグメント マネージャーに追加しました。
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 がもう 1 回呼び出されます。タブを 10 回切り替える = OnCreateView への 11 回の呼び出し。これは明らかに間違っています。
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);
}
タブの切り替えと向きの変更の両方で、すべてが完全に機能しているようです。