Подтвердить что ты не робот

Использование ActionBar Up Навигация в фрагментах мастера/детали

У меня есть приложение с макетом/макетом (1 активность, 1 фрагмент ListView и 1 фрагмент детали). Когда пользователь нажимает элемент в ListView, транзакция фрагмента создает фрагмент детали на правой панели, который содержит информацию, соответствующую этому элементу. Когда показан фрагмент детали, я скрываю кнопки/элементы начальных кнопок действий и показываю 3 новых элемента AB (done/delete/cancel). Пользователь может очистить правую панель и вернуться в исходное состояние пользовательского интерфейса, нажав кнопку "Назад" или нажав один из трех элементов AB.

Проблема, с которой я сталкиваюсь, заключается в том, что когда пользователь выбирает значок дома приложения (т.е. "вверх" ), активность загружается повторно (т.е. анимация, указывающая, что действие запускается, можно рассматривать как действие бар и пользовательский интерфейс перерисовываются). Проблема возникает только при нажатии значка дома приложения. Если пользователь нажимает кнопку "Назад" или кнопку панели "Отменить/сделать/удалить", фрагмент просто удаляется с правой панели, и пользовательский интерфейс возвращается в исходное состояние без "повторной загрузки".

XML-макет для действия следующий (внутри LinearLayout; prettify скрывает эту строку):   

<fragment class="*.*.*.ListFragment"
        android:id="@+id/titles" android:layout_weight="1"
        android:layout_width="0px"
        android:layout_height="match_parent" />

<FrameLayout android:id="@+id/details" android:layout_weight="2"
        android:layout_width="0px"
        android:layout_height="match_parent" />

ПодробностиFragement содержит оператор actionBar.setDisplayHomeAsUpEnabled в методе onCreate:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);


    ActionBar actionBar = getSherlockActivity().getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);

}

Для фрагмента ListView и фрагментов Detail в фрагментах реализованы метод onCreateOptionsMenu() и onOptionsItemSelected(). Ниже кода фрагмента детали:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.edit_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    // some variable statements...

    switch (item.getItemId()) {
        case android.R.id.home:
            //Toast.makeText(getSherlockActivity(), "Tapped home", Toast.LENGTH_SHORT).show();
            onHomeSelectedListener.onHomeSelected();
            return true;

        case R.id.menu_edit_item_done:
            editedTask.setTitle(editedTaskTitle);
            onTaskEditedListener.onTaskEdited(editedTask, UPDATE_TASK, true);
            return true;

        default:
            return super.onOptionsItemSelected(item);

    }
}

В действии хоста я реализую onHomeSelectedListner для обработки значка на домашней странице приложения (то есть "вверх" ):

public void onHomeSelected(){

    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction ft = manager.beginTransaction();
    TaskFragment taskFragment = (TaskFragment)getSupportFragmentManager().findFragmentById(R.id.details);
    ft.remove(taskFragment);
    ft.commit();
    manager.popBackStack();

}

Слушатель активности, которому поручено обрабатывать все другие кнопки панели действий (т.е. done/delete/cancel), является onTaskEditedListener, и помимо другого кода, который обрабатывает некоторые данные, он имеет те же операции с фрагментами, которые показаны выше.

Обновить (1/24) Основываясь на обратной связи tyczj и straya, я разместил операторы журнала внутри onCreate(), onResume(), onPause() для определения различий между onHomeSelected и onTaskEdited слушателями. Я могу подтвердить, что во время события "вверх навигации" (т.е. OnHomeSelected) onPause() вызывается onCreate() и onResume(). В то время как во время вызова onTaskEdited (т.е. Кнопки возврата или завершения/удаления/отмены) ни одно из этих событий не вызывается.

Обновление (1/25) Основываясь на предположении Марка Мерфи, я прокомментировал вызов метода onHomeSelected в инструкции case case.R.id.home, чтобы посмотреть, что будет делать Activity. Мысль заключалась в том, что приложение ничего не сделало бы с тех пор, пока не будет никаких утверждений. Оказывается, это не так. Даже без вызова метода слушателя (то есть, который удаляет фрагмент), активность перезапускается и фрагмент детали удаляется из контейнера фрагментов.

Обновление (2/28) Я временно обманывал тот факт, что мое основное действие было перезапущено, отключив анимацию окна (как указано в моем собственном ответе). Однако после дальнейшего тестирования я обнаружил ошибку. Благодаря образцу кода Вольфрама Риттмейера я смог выяснить истинную причину (причины), почему моя активность была перезапущена (в макете/подробном одиночном макете) во время навигации: 1) Хотя я использовал этот "onHomeSelectedListener" для правильного удаления фрагмента из backstack, у меня все еще был некоторый остаток кода в элементе ListView onOptionsItemSelected, который создавал новое намерение начать хостинг. Вот почему нажатие на значок приложения домой возобновило действие. 2) В моей последней реализации (показано в моем собственном ответе) я избавился от onHomeSelectedListener в действии и заменил цель startActivity (т.е. код нарушения) внутри ListView onOptionsItemSelected, чтобы использовать удаление фрагмента + код popBackStack изначально в onHomeSelectedListener.

4b9b3361

Ответ 1

После долгих исследований и опрокидывания выяснилось, что только причина, по которой моя активность перезапускалась во время навигации вверх для конфигурации master/detail, заключалась в том, что я оставил некоторый код в элементе ListView Fragment onOptionsItemSelected, который создавал намерение запустить главную в дополнение к моему коду транзакции с полным фрагментом в другом месте. Ниже приведена окончательная реализация, с которой я получил "навигацию вверх" для правильной работы на обеих телефонах (несколько видов деятельности) и планшетных (однопроцессорных/многопанельных) конфигурациях. Благодаря Wolfram Rittmeyer за пару советов в его коде (ссылка в разделе комментариев), которые помогут мне определить мою проблему!

Основная активность: Хост фрагментов и выполнение некоторых других операций, специфичных для приложения

Фрагмент списка ListView: Ручки "вверх по навигации в конфигурации таблицы

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            if(mDualPane){
                FragmentManager manager = getSherlockActivity().getSupportFragmentManager();
                FragmentTransaction ft = manager.beginTransaction();
                DetailFragment detailFragment = (DetailFragment)manager.findFragmentById(R.id.details);
                ft.remove(detailFragment);
                ft.commit();
                manager.popBackStack();
                getSherlockActivity().getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                getSherlockActivity().getSupportActionBar().setHomeButtonEnabled(false);
            }
            return true;

        // Other case statements...

        default:
            return super.onOptionsItemSelected(item);
    }
}

Подробнее Фрагмент: Управляет навигацией в конфигурации телефона

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);

    // Sets "up navigation" for both phone/tablet configurations
    ActionBar actionBar = getSherlockActivity().getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case android.R.id.home:
            if(!mDualPane){
                Intent parentActivityIntent = new Intent(getSherlockActivity(), MainActivity.class);
                parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(parentActivityIntent);
                getSherlockActivity().finish();
            }
            return true;

        // Other case statements...

        default:
            return super.onOptionsItemSelected(item);
    }

}

Ответ 2

Если вы посмотрите на шаблон дизайна навигации, вы увидите, что хотите вернуться к стартовой активности при нажатии кнопки "Дом".

Итак, скажите, что у вас есть 2 действия, называя их A1 и A2. Нажатие на что-то в A1 приведет вас к A2. Если пользователь нажал кнопку "домой", вы должны вернуть их в A1, очистив стек всего до тех пор, пока эта активность не будет выглядеть как

Intent intent = new Intent(this, A1.class);  
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

это то, что делает флаг Intent.FLAG_ACTIVITY_CLEAR_TOP

Если установлено, и запущенная деятельность уже запущена в текущей задаче, вместо того, чтобы запускать новый экземпляр этого действия, все остальные действия поверх него будут закрыты, и это намерение будет доставлено в (сейчас сверху) старой деятельности как нового намерения.

Например, рассмотрите задачу, состоящую из действий: A, B, C, D. Если D вызывает startActivity() с намерением, который разрешает компонент активности B, то C и D будут завершены и B получит данное намерение, в результате чего стек теперь будет: A, B.`

Текущий исполняемый экземпляр действия B в приведенном выше примере либо получит новое намерение, которое вы начинаете здесь, в методе onNewIntent(), либо сам закончите и перезапустите с новым намерением. Если он объявил свой режим запуска "множественным" (по умолчанию), и вы не установили FLAG_ACTIVITY_SINGLE_TOP в одном и том же намерении, он будет завершен и заново создан; для всех других режимов запуска или если установлен FLAG_ACTIVITY_SINGLE_TOP, этот Intent будет доставлен в текущий экземпляр onNewIntent().

Этот режим запуска также можно использовать для хорошего эффекта в сочетании с FLAG_ACTIVITY_NEW_TASK: если он используется для запуска корневой активности задачи, он приведет к запуску текущего исполняемого экземпляра этой задачи на передний план, а затем очистит его до корня государство. Это особенно полезно, например, при запуске активности из диспетчера уведомлений.

Ответ 3

не: break и затем возвращать super.onOptionsItemSelected(item), а просто: return true;

UPDATE:

Итак, вы говорите, что активность "перезапущена" на основе того, что вы видите в "Представлениях", но можете ли вы подтвердить, что может или не может произойти с Activity (и фрагментами, если на то пошло), используя ведение журнала в различном жизненном цикле методы? Таким образом, вы можете быть уверены в том, каково текущее (ошибочное) поведение, прежде чем двигаться вперед с диагнозом.

UPDATE:

Хорошо, хорошо, чтобы быть уверенным в поведении:) Теперь о вашем вопросе "Каков правильный способ реализации" навигации вверх "для макета/макета (1 активность /2 фрагмента)?": Типичным способом является то, что 2 фрагмента добавлены в один фрагмент FragmentTransaction, и вы просто popBackStack, чтобы удалить их и вернуться к тому, что было в предыдущем состоянии. Я думаю, что вы удваиваете, вручную удаляя фрагмент внутри FragmentTransaction, а затем выскакивая назад. Попробуйте просто popBackStack. О, и просто быть уверенным и последовательным, поскольку вы используете ActionBarSherlock и support.v4, вы используете FragmentActivity (а не Activity) и SherlockFragment?

Ответ 4

Я думаю, что вы должны обрабатывать кнопку "Вверх" только внутри этой операции. Если вы находитесь в телефоне, кнопка "вверх" будет обрабатываться действием, которое действует как обертка этого фрагмента, в планшете (шаблон мастера/детали), который вы вообще не хотите.