Удаление активности из стека истории


382

Мое приложение показывает активность регистрации в первый раз, когда пользователь запускает приложение, выглядит так:

  1. ActivitySplashScreen (добро пожаловать в игру, зарегистрировать аккаунт?)
  2. ActivitySplashScreenSignUp (отлично, заполните эту информацию)
  3. ActivityGameMain (основной экран игры)

поэтому действия запускаются друг в друге именно в таком порядке, когда пользователь нажимает кнопку на каждом экране.

Когда пользователь переходит от действия № 2 к № 3, возможно ли полностью стереть № 1 и № 2 из стека истории? Мне бы хотелось, чтобы, если пользователь находится на # 3 и нажимает кнопку «Назад», он просто переходил на домашний экран, а не обратно на заставку.

Я думаю, что могу сделать это с помощью задач (т.е. начать новую задачу на # 3), но хотел посмотреть, есть ли более простой метод,

Спасибо


Находясь на главном экране, когда пользователь возобновляет ваше приложение, оно переводит его в ActivitySplashScreen или ActivityGameMain?
Тамил

Ответы:


632

Вы можете достичь этого путем установки android:noHistory атрибута для "true"в соответствующих <activity>записей в вашем AndroidManifest.xmlфайле. Например:

<activity
    android:name=".AnyActivity"
    android:noHistory="true" />

12
Это лучший способ сделать это.
Шкшнейдер

22
Эквивалентно вы можете использовать FLAG_ACTIVITY_NO_HISTORY.
Тимммм

34
Как я могу добиться этого из кода? Потому что я не хочу делать это все время. Я хотел бы удалить данную деятельность из истории только при определенных условиях.
Намрата

8
Просто имейте в виду, что использование атрибута noHistory завершит эту деятельность, что может вызвать непредвиденное поведение, например, при входе в систему через G +. См .: stackoverflow.com/questions/20383878/… Мне потребовалось некоторое время, чтобы найти эту ошибку, поскольку мое приложение продолжало падать без каких-либо следов.
Акапулько

13
Сложно скопировать нужный флаг, так как это ссылка, поэтому здесь можно легко скопировать. android:noHistory="true"
MirroredFate

137

Вы можете использовать переадресацию, чтобы удалить предыдущее действие из стека действий при запуске следующего. В APIDemos есть пример этого , но в основном все, что вы делаете, это звоните finish()сразу после звонка startActivity().


1
Привет, Даниэль, я прочитал пример, но это очистит стек истории только одним действием, не так ли? Если мой стек выглядит как A, B, и я запускаю C, я хочу, чтобы C был новым корнем и полностью очистил A и B. В примере sdk вызов метода finish () из B оставил бы мне стек A C, не так ли? Спасибо.
Марк

1
Вы можете очистить A при запуске B и очистить B при запуске C; однако, я полагаю, что тогда вы не сможете отступить от B к A, если вы этого хотите. Я должен подумать об этом больше, если это проблема.
Дэн Лью

3
Отметьте, чтобы достичь того, что вы хотите, вы должны использовать флаг: FLAG_ACTIVITY_CLEAR_TOP. Я надеюсь, что это помогает.
Франциско Младший

3
FLAG_ACTIVITY_CLEAR_TOPне будет работать, потому что C еще не в заднем стеке.
Тимммм

1
@DanielLew В APIDemos очень много примеров. У вас есть название предложенного примера?
Стефан

52

Да, взгляните на Intent.FLAG_ACTIVITY_NO_HISTORY .


46
Обратите внимание, что это не устанавливает историю для действия, которое вы запускаете. Чтобы не было истории действия, с которого вы запускаете, я просто установил его android:noHistory="true"в манифесте.
georgiecasey

1
Это хорошо работает. Используйте, intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)чтобы установить этот флаг.
Vovahost

1
@georgiecasey это полезно, когда иногда вы хотите сохранить это в истории, а иногда вы не хотите в истории.
Вихан Верма

24

Это, вероятно, не идеальный способ сделать это. Если у кого-то есть лучший способ, я буду с нетерпением ждать его реализации. Вот как я выполнил эту конкретную задачу с SDK до версии 11.

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

    ... interesting code stuff ...
    Intent i = new Intent(MyActivityThatNeedsToGo.this, NextActivity.class);
    startActivityForResult(i, 0);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == R.string.unwind_stack_result_id) {
        this.setResult(R.string.unwind_stack_result_id);
        this.finish();
    }
}

тогда тот, который должен отключить цепочку всплывающих окон из стека, должен просто вызвать его, когда вы хотите его инициировать:

NextActivity.this.setResult(R.string.unwind_stack_result_id);
NextActivity.this.finish();

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


В случае, если кто-нибудь столкнется с этим позже, я подумал, что может оказаться важным знать, что если вы повернули экран, Android автоматически перезапустит ваше приложение, когда вы вытолкнете последнюю активность из стека. Просто знайте об этом!
Трэвис

Это хороший ответ, если вы хотите только условно удалить действие из стека в зависимости от того, что пользователь делает в следующем
задании

23

Один из способов, который работает до API 11, - это ActivityGameMainсначала запустить , а затем onCreateиз этого действия начать свою ActivitySplashScreenдеятельность. ActivityGameMainНе будет появляться , как вы называете startActivity слишком рано для всплеска.

Затем вы можете очистить стек при запуске ActivityGameMain, установив эти флаги в Intent:

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

Вы также должны добавить это в ActivitySplashScreen:

@Override
public void onBackPressed() {
    moveTaskToBack(true);
}

Так что, нажимая на эту активность, вы не вернетесь к вашей ActivityGameMain.

Я полагаю, что вы не хотите, чтобы экран-заставка возвращался, либо для достижения этого я предлагаю установить его noHistoryв своем AndroidManifest.xml. Затем поместите goBackPressedкод в свой ActivitySplashScreenSignUpкласс.

Однако я нашел несколько способов сломать это. Запустите другое приложение с уведомлением, пока ActivitySplashScreenSignUpотображается и история изменений не сбрасывается.

Единственный реальный способ обойти это в API 11:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);

20

Я использую этот способ.

Intent i = new Intent(MyOldActivity.this, MyNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);

Спасибо. Я нашел это полезным в том случае, если в моем меню была кнопка «Домой», и я не хотел, чтобы сгруппированные действия появлялись после того, как пользователь нажал на кнопку «Домой».
Гитеш

8

Я знаю, что опоздал на это (прошло два года с тех пор, как был задан вопрос), но я достиг этого, перехватив нажатие кнопки «назад». Вместо того, чтобы проверять конкретные действия, я просто смотрю на счетчик, и если он меньше 3, он просто отправляет приложение обратно (приостанавливает приложение и возвращает пользователя к тому, что было запущено перед запуском). Я проверяю менее трех, потому что у меня только один вводный экран. Кроме того, я проверяю счетчик, потому что мое приложение позволяет пользователю вернуться к главному экрану через меню, что позволяет ему выполнять резервное копирование через другие экраны, как обычно, если в стеке есть действия, отличные от вступительного экрана.

//We want the home screen to behave like the bottom of the activity stack so we do not return to the initial screen
//unless the application has been killed. Users can toggle the session mode with a menu item at all other times.
@Override
public void onBackPressed() {
    //Check the activity stack and see if it's more than two deep (initial screen and home screen)
    //If it's more than two deep, then let the app proccess the press
    ActivityManager am = (ActivityManager)this.getSystemService(Activity.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(3); //3 because we have to give it something. This is an arbitrary number
    int activityCount = tasks.get(0).numActivities;

    if (activityCount < 3)
    {
        moveTaskToBack(true);
    }
    else
    {
        super.onBackPressed();
    }
}

7

В манифест вы можете добавить:

android:noHistory="true"

<activity
android:name=".ActivityName"
android:noHistory="true" />

Вы также можете позвонить

finish()

сразу после вызова startActivity (..)


2
Лучше использовать флаги активности, чем помещать вещи в манифест.
Тревор Харт


4

Это безумие, что никто не упомянул это элегантное решение. Это должен быть принятый ответ.

SplashActivity -> AuthActivity -> DashActivity

if (!sessionManager.isLoggedIn()) {
    Intent intent = new Intent(context, AuthActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
    context.startActivity(intent);
    finish();
} else {
   Intent intent = new Intent(context, DashActivity.class);
   context.startActivity(intent);
    finish();
}

Ключевым моментом здесь является использование intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); для посредника Activity. Как только это среднее звено будет разорвано, DashActivityзавещание будет первым и последним в стеке.

android:noHistory="true"это плохое решение, так как оно вызывает проблемы при использовании Activityобратного вызова, например onActivityResult. Это рекомендуемое решение и должно быть принято.


1
Этот флаг звучал слишком хорошо, чтобы быть правдой. FLAG_ACTIVITY_NO_HISTORY работает хорошо и, как и следовало ожидать, пока приложение не будет переведено в фоновый режим, а затем снова на передний план, сохраняя активность с флагом в верхней части стека. При переходе в фоновый режим активность уничтожается. Вернувшись в приложение, вы увидите предыдущую активность из стека. Я определенно не хотел такого поведения.
NeverwinterMoon

4

Уже слишком поздно, но надеюсь, что это поможет. Большинство ответов не указывают в правильном направлении. Для такой вещи есть два простых флага.

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

Из документов Android:

public static final int FLAG_ACTIVITY_CLEAR_TASK Добавлено на уровне API 11

If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the

активность должна быть очищена до начала действия. Таким образом, действие становится новым корнем в противном случае пустой задачи, и все старые действия завершаются. Это можно использовать только в сочетании с FLAG_ACTIVITY_NEW_TASK.


1

Просто вызовите this.finish () перед startActivity (намерением)

       Intent intent = new Intent(ActivityOne.this, ActivityTwo.class);
        this.finish();
        startActivity(intent);

пользователи, у которых есть ошибка «this», должны изменить ее на «ActivityOne.this»
ninbit

1

Удаление действия из истории выполняется установкой флажка перед действием, которое вы не хотите

A-> B-> C-> D

Предположим, что A, B, C и D - 4 Действия, если вы хотите очистить B и C, тогда установите флаг

intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

В деятельности А и Б

Вот бит кода

Intent intent = new Intent(this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);

0
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            super.finishAndRemoveTask();
        }
        else {
            super.finish();
        }

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.