Добре, най-накрая разбрах това:
Както беше предложено по-горе, първо промених създаването на фрагменти да се извършва програмно и ги добавих към мениджъра на дъщерни фрагменти, така:
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, но забелязах, че OnCreateView на стария Lhs/RhsFragment също ще бъде извикан. Така че след всяко превключване на раздели ще има още едно извикване на OnCreateView. Превключване на раздели 10 пъти = 11 извиквания на OnCreateView. Това очевидно е грешно.
Разглеждайки изходния код за FragmentTabHost, виждам, че той просто отделя и прикачва отново фрагмента от съдържанието на раздела при превключване на раздели. Изглежда, че 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);
}
Сега всичко изглежда работи перфектно, както при превключване на раздели, така и при промяна на ориентация.
person
Brad Robinson
schedule
14.03.2013