У меня есть приложение для Android, написанное с использованием Xamarin, но мой вопрос относится и к не Xamarin. У меня есть класс MainActivity (как действие), который просто размещает макет фрейма в виде контейнера фрагмента. Мое приложение состоит из нескольких фрагментов, по которым я перемещаюсь назад и вперед. Да, я знаю, что ViewPager подходит для этой задачи и решит мою проблему, но по причинам, выходящим за рамки этого поста, я не хочу использовать ViewPager.
Все, что у меня есть, это в основном простые кнопки (например, следующая и предыдущая), которые используются для навигации. При навигации я добавляю фрагменты в задний стек, если они еще не существуют. Если они существуют, я обязательно добавлю задний стек вместо создания нескольких дублирующих экземпляров. Поэтому, если в моем приложении только 4 фрагмента, в моем заднем стеке будет только 4 элемента.
Мой вопрос касается событий жизненного цикла. Как только фрагмент создается один раз, когда будут возникать события жизненного цикла (OnCreate и т. Д.), Они никогда не будут вызываться снова при простом переходе от фрагмента к фрагменту и обратно (при условии, что они были созданы один раз и сидят в заднем стеке).
Поэтому я ищу чистый способ вызывать событие для фрагмента каждый раз, когда он останавливается или возобновляется с помощью навигации, подобно onPause и onResume, которые обычно происходят.
Я немного прочитал и обнаружил, что не могу проверить скрытое свойство в этом случае, потому что это происходит только во время скрытия или показа фрагмента, и я не делаю этого здесь, получение заднего стека не вызывает скрытое свойство или событие.
Итак, я создал интерфейс, подобный этому:
interface ICustomFragmentLifecycle
{
void onPauseFragment();
void onResumeFragment();
}
Затем я удостоверяюсь, что каждый фрагмент реализует этот интерфейс, который дает мне методы паузы и возобновления для каждого фрагмента, где я могу выполнять работу, которую я хочу сделать.
Проблема в MainActivity, где я должен вызывать эти события. Каждый раз, когда нажимается кнопка для навигации, я получаю это на MainActivity, что хорошо, поэтому я могу действовать по нему и использовать его для вызова пользовательских событий в интерфейсе. Мне также нужно сделать что-то подобное с кнопкой возврата. Итак, вот как я обрабатываю кнопку возврата:
public override void OnBackPressed()
{
//When the back button is pressed, we need to first pop the back stack.
if(SupportFragmentManager.BackStackEntryCount > 0)
{
//First, raise the pause method on the current fragment
RaiseCustomFragmentOnPause();
if(SupportFragmentManager.BackStackEntryCount > 1)
//Now we should resume the fragment that is showing
RaiseCustomFragmentOnResume();
SupportFragmentManager.PopBackStack();
//Check and see if we just popped the last one and now there are none.
if(SupportFragmentManager.BackStackEntryCount == 0)
MainLayoutEnabled(true);
return;
}
}
И, наконец, в методах, которые вызываются для вызова паузы или возобновления, это код:
private void RaiseCustomFragmentOnPause()
{
//This will get the current fragment from the stack.
var fragIdToPause = SupportFragmentManager.BackStackEntryCount - 1;
var fragBackEntry = SupportFragmentManager.GetBackStackEntryAt(fragIdToPause);
var fragTag = fragBackEntry.Name;
ICustomFragmentLifecycle fragmentToPause = (ICustomFragmentLifecycle)SupportFragmentManager.FindFragmentByTag(fragTag);
fragmentToPause.onPauseFragment();
}
private void RaiseCustomFragmentOnResume()
{
//This will get the previous fragment, before the current one, from the stack.
var fragIdToPause = SupportFragmentManager.BackStackEntryCount - 2;
var fragBackEntry = SupportFragmentManager.GetBackStackEntryAt(fragIdToPause);
var fragTag = fragBackEntry.Name;
ICustomFragmentLifecycle fragmentToResume = (ICustomFragmentLifecycle)SupportFragmentManager.FindFragmentByTag(fragTag);
fragmentToResume.onResumeFragment();
}
Меня интересует, прежде всего, хороший ли это подход или есть что-то более изящное, чего мне не хватает. Конкретная проблема, с которой я сталкиваюсь, это то, что время от времени я получаю исключение нулевой ссылки методом
GetBackStackEntryAt ()
Я подозреваю, что мой метод получения текущих и предыдущих записей в стеке обратно, основанный только на вычитании одного (для текущего) и двух (для предыдущего), некорректен. Я пытался описать это в вызывающей стороне этих методов, методе кнопки «назад», проверяя, чтобы убедиться, что в стеке есть хотя бы один или два элемента, прежде чем я вызову их, но все равно кажется, что несинхронизировано и что-то испортилось.
Мысли
Спасибо!