Как проверить, является ли действие последним в стеке действий для приложения?


122

Я хочу знать, вернется ли пользователь на главный экран, если он выйдет из текущего действия.



43
Только что узнал, что в Activity есть функция isTaskRoot, которая, я думаю, может вам помочь.
H9kDroid

Ответы:


116

ОБНОВЛЕНИЕ (июль 2015 г.):

Поскольку getRunningTasks () устарел, из API 21 лучше следовать raukodraug ответ или Эд Бернетт один (я бы предпочел второй).


Есть возможность проверить текущие задачи и их стек с помощью ActivityManager .

Итак, чтобы определить, является ли действие последним:

  • запросить разрешения android.permission.GET_TASKS в манифесте.
  • Используйте следующий код:

    ActivityManager mngr = (ActivityManager) getSystemService( ACTIVITY_SERVICE );
    
    List<ActivityManager.RunningTaskInfo> taskList = mngr.getRunningTasks(10);
    
    if(taskList.get(0).numActivities == 1 &&
       taskList.get(0).topActivity.getClassName().equals(this.getClass().getName())) {
        Log.i(TAG, "This is last activity in the stack");
    }

Обратите внимание, что приведенный выше код будет действителен только в том случае, если у вас одна задача. Если есть вероятность, что для вашего приложения будет существовать такое количество задач - вам нужно будет проверить другие элементы taskList . Подробнее о задачах Задачи и Back Stack



25
H9kDroid сделал правильное предложение. Выбранный ответ - взлом. Надо делать это правильно, используя isTaskRoot()метод.
Sufian

@Sufian где конкретно взлом? Код логичен и использует открытые API-интерфейсы Android таким образом, как они предназначены для использования (например, getRunningTasks следует использовать для запуска задач, и его можно вызвать только с целью анализа этих задач). Использование get (0) хорошо документировано и логично: «Возвращать список задач, которые выполняются в данный момент, причем самые свежие будут первыми, а старые - после».
sandrstar

2
getRunningTasks () устарел на уровне API 21.
gilchris

Могу ли я сделать то же самое для фрагментов. Если да, то как? Пожалуйста, помогите
Сагар Деванга

1
@ Мистер Дрю видит ответ с наибольшим количеством голосов от @ raukodraug
Дэвид Вассер

167

Я собираюсь опубликовать комментарий @ H9kDroid как лучший ответ здесь для людей, у которых есть аналогичный вопрос.

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

надеюсь, это поможет


1
не могли бы вы предоставить одну строку кода, чтобы было понятно, как использовать isTaskRoot. Спасибо.
Кавиш Канвал,

18
@TheHunterif (isTaskRoot()) { // do something }
howettl

3
Единственная проблема в том, что в <= 4.4 я вижу, что он ведет себя иначе, чем в> = 5.x. Кажется, всегда возвращает false.
chubbsondubs 01

Я думаю, вам следует рассмотреть возможность включения примера кода, приведенного в комментариях, в ответ, чтобы облегчить его будущим читателям.
Исак

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

19

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

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

В вашей деятельности

   @Override
    public void onBackPressed() {

        if(isTaskRoot()){
            startActivity(new Intent(currentActivityName.this,ActivityNameYouWantToOpen.class));
            // using finish() is optional, use it if you do not want to keep currentActivity in stack
            finish();
        }else{
            super.onBackPressed();
        }

    }


5

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

Если вы пытаетесь сохранить данные, поместите код сохранения данных в свой метод onPause (). Если вы пытаетесь дать пользователю возможность изменить свое мнение о существующем приложении, вы можете перехватить клавиши вверх / вниз для клавиши Back и метода onBackPressed () и представить им сообщение «Вы уверены?» Подсказка.


1
Как насчет того, чтобы служба работала до тех пор, пока пользователь не покинул активность? Я не могу перехватить какие-либо функции, такие как onStop, потому что они могут быть вызваны после выключения экрана.
Майкл

2
Если фоновая служба запускает Activity, возможно, вы захотите узнать, единственное ли это действие в стеке.
Matt W

4

Один из способов отслеживать это - включить маркер, когда вы начинаете новое действие, и проверить, существует ли маркер.

Каждый раз, когда вы начинаете новое занятие, вставляйте маркер:

newIntent=new Intent(this, NextOne.class);
newIntent.putExtra(this.getPackageName()+"myself", 0);
startActivity(newIntent);

И вы можете проверить это следующим образом:

boolean islast=!getIntent().hasExtra(this.getPackageName()+"myself")

1
Не работает, если действие прекращено и стек действий реконструирован - каждое действие по запросу.
AlikElzin-kilaka 03

3

Проблема с использованием решения sandrstar ActivityManagerзаключается в том, что вам нужно разрешение на получение задач таким образом. Я нашел способ получше:

getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)

Элемент Activityв нижней части стека должен всегда получать эту категорию по умолчанию, в то время как другие действия не должны ее получать.
Но даже если это не удается на некоторых устройствах, вы можете установить его при запуске Activity:

Intent intent = new Intent(startingActivity, SomeActivityClass.class);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
activity.startActivity(intent);

Что делать, если действие открывается из push-уведомления? У них нет CATEGORY
LAUNCHER

Я совершенно уверен, что вторая часть моего ответа все еще применима. Вы можете установить категорию как подсказку в намерении. В этом случае, возможно, в контексте вашего уведомления. Помимо этого, вы также можете использовать для этого флаги. см. эту ссылку для создания уведомления с намерением: stackoverflow.com/questions/13716723/…
A. Binzxxxxxx 05

Тем не менее, если ваше самое старое действие - MainActivity, и теперь оно возобновлено, а затем вы получаете push-уведомление и устанавливаете pendingIntent для открытия с помощью CATEGORY_LAUNCHER, тогда у вас будет 2 действия с этой категорией. Наверное, на других задачах
nbtk 06

Я не совсем уверен, как это работает с уведомлениями. Я никогда не использовал их так, как вы делаете это здесь. Я уверен, что есть простой способ сделать это с помощью этого подхода, но я не трогал код Android с первого квартала 2014 года. Может быть, вы хотите использовать вторую категорию для этого случая? Или какой-нибудь флаг? Но я полагаю, что так и должно работать. Как насчет того, чтобы начать основное действие и добавить какую-то метаинформацию, чтобы открыть правильное действие?
A. Binzxxxxxx 07

2

Я создал базовый класс для всех своих действий, расширяющий AppCompatActivity и имеющий статический счетчик:

public abstract class BasicActivity extends AppCompatActivity {
    private static int activityCounter = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ++activityCounter;
        ...
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        --activityCounter;
        if(activityCounter==0) {
            // Last instance code...
        }
    }

    public boolean isLastInstance() { return (activityCounter==1); }
}

Пока это работает достаточно хорошо; и независимо от версии API. Конечно, для этого требуется, чтобы все действия расширяли этот базовый класс - что они и делают, в моем случае.

Изменить: я заметил один случай, когда счетчик опускается до нуля до полного выхода из приложения, то есть когда ориентация изменяется и открывается только одно действие. Когда ориентация изменяется, действие закрывается и создается другое, поэтому onDestroyedвызывается для последнего действия, а затем onCreateвызывается, когда такое же действие создается с измененной ориентацией. Это поведение необходимо учитывать; Возможно, можно использовать OrientationEventListener .


0

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


9
Это не сработает, поскольку getCallingActivity () вернет значение null, если действие не было запущено через startActivityForResult ().
H9kDroid 03

0

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

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

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