Android: как проверить, работает ли активность?


152

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

if(activityrunning == activity1)
//do this
else if (activityrunning == activity2)
//do something else

Чтобы проверить, выполняется ли действие или нет, вы можете пройти через этот ответ: stackoverflow.com/a/39079627/4531507
Рахул Шарма

Ответы:


227

Вы можете использовать staticпеременную в деятельности.

class MyActivity extends Activity {
     static boolean active = false;

      @Override
      public void onStart() {
         super.onStart();
         active = true;
      } 

      @Override
      public void onStop() {
         super.onStop();
         active = false;
      }
}

Единственный недостаток в том, что если вы используете его в двух действиях, которые связаны друг с другом, то onStopпервое вызывается после onStartвторого. Так что оба могут быть правдой кратко.

В зависимости от того, что вы пытаетесь сделать (обновить текущую активность из службы?). Вы можете просто зарегистрировать статический прослушиватель в службе в вашем onStartметоде активности, тогда правильный слушатель будет доступен, когда ваша служба захочет обновить пользовательский интерфейс.


5
Кто-то указал мне на это, что предпочтение Sharedpreference должно быть выше статической переменной из-за проблем с утечкой памяти.
Аюш Гоял

13
Что делать, если выполняются разные действия одного и того же класса? Что делать , если вы расширяете MyActivityс MyChildactivityи хотите проверить , если ребенок активен?
Мистер Смит

2
В зависимости от вашего определения «работает» вы можете изменить состояние переменной в onResume и onPause ....
Г. Блейк Майке

5
Это решение не является хорошим решением вообще. Допустим, ваша активность вызывает фрагмент, например, фрагмент будет находиться над активностью, но активность не будет вызывать onPause, и если вы закроете фрагмент onStop, onStart или любые другие методы жизненного цикла, они также не будут вызваны. Лучшее решение - проверить в своем классе приложения видимость, как описано здесь: stackoverflow.com/questions/18038399/…
portfolioiobuilder

6
Если вы порекомендуете статику, вы получите -1 от меня
Matei Suica

53

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

Это решение не было доступно до выпуска компонентов архитектуры Android.

Активность хотя бы частично видна

getLifecycle().getCurrentState().isAtLeast(STARTED)

Деятельность на переднем плане

getLifecycle().getCurrentState().isAtLeast(RESUMED)

3
getLifecycle (). getCurrentState (). isAtLeast (Lifecycle.State.RESUMED)
Радхи

43

Я думаю, что более ясно, как это:

  public boolean isRunning(Context ctx) {
        ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

        for (RunningTaskInfo task : tasks) {
            if (ctx.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName())) 
                return true;                                  
        }

        return false;
    }

2
Я стараюсь избегать создания временных переменных перед циклом for; для (задача RunningTaskInfo: ActivityManager.getRunningTasks (Integer.MAX_VALUE)) {...
mikebabcock

Как я могу вызвать эту функцию?
Behzad

1
как обычно, метод, который вы можете вызывать внутри своего класса как «функцию», вам нужен пример?
Ксенион

10
От developer.android.com/reference/android/app/… "Это никогда не должно использоваться для базовой логики в приложении, такой как выбор между различными поведениями на основе информации, найденной здесь. Такое использование не поддерживается и, скорее всего, прекратит работу в будущем."
joe_deniable

15
Начиная с уровня API 21 (Android 5.0 Lollipop) этот метод устарел.
AxeEffect

30

Опция без использования вспомогательной переменной:

activity.getWindow().getDecorView().getRootView().isShown()

где активность fe: this или getActivity ().

Значение, возвращаемое этим выражением, изменяется в onStart () / onStop (), которые являются событиями, которые запускают / останавливают показ макета действия на телефоне.


16
почему не использовать Activity#getWindow().getDecorView().isShown()?
Джанлука П.

24

Я использовал метод MyActivity.class и getCanonicalName и получил ответ.

protected Boolean isActivityRunning(Class activityClass)
{
        ActivityManager activityManager = (ActivityManager) getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

        for (ActivityManager.RunningTaskInfo task : tasks) {
            if (activityClass.getCanonicalName().equalsIgnoreCase(task.baseActivity.getClassName()))
                return true;
        }

        return false;
}

1
Как уже упоминалось ранее, это может быть не очень хорошая идея использования , getRunningTasks()как это было устаревшим: androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/...
Vitalii Дмитриев

21

Гораздо лучший способ, чем использовать статическую переменную и следовать ООП

Shared Preferencesможет использоваться для обмена переменными с другими activitiesи службами из одногоapplication

    public class example extends Activity {

    @Override
    protected void onStart() {
        super.onStart();

        // Store our shared preference
        SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
        Editor ed = sp.edit();
        ed.putBoolean("active", true);
        ed.commit();
    }

    @Override
    protected void onStop() {
        super.onStop();

        // Store our shared preference
        SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
        Editor ed = sp.edit();
        ed.putBoolean("active", false);
        ed.commit();

    }
}

Используйте общие настройки. У него самая достоверная информация о состоянии, меньше проблем с переключением / уничтожением приложений, что избавляет нас от необходимости запрашивать еще одно разрешение и дает нам больше контроля над тем, когда наша деятельность на самом деле самая высокая. см подробности здесь ABD здесь также


Спасибо. Но нужен ли onResume братан?

1
Это зависит от того, что вы понимаете под активным. Согласно моему коду активность находится в стеке, тогда она активна. И если вы хотите обрабатывать видимое или нет, то вы можете использовать onResume
Zar E Ahmer

19
Это прерывается, когда активность убивают без звонкаonStop()
Марсель Бро

3
Что произойдет, если приложение выйдет из строя?
ucMedia

1
Это очень опасное «решение».
Firzen

9

Это код для проверки того, запущена ли конкретная служба. Я вполне уверен, что он может работать и для действия, если вы измените getRunningServices с помощью getRunningAppProcesses () или getRunningTasks (). Посмотрите здесь http://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses ()

Измените Constants.PACKAGE и Constants.BACKGROUND_SERVICE_CLASS соответственно

    public static boolean isServiceRunning(Context context) {

    Log.i(TAG, "Checking if service is running");

    ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);

    List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

    boolean isServiceFound = false;

    for (int i = 0; i < services.size(); i++) {

        if (Constants.PACKAGE.equals(services.get(i).service.getPackageName())){

            if (Constants.BACKGROUND_SERVICE_CLASS.equals(services.get(i).service.getClassName())){
                isServiceFound = true;
            }
        }
    }

    Log.i(TAG, "Service was" + (isServiceFound ? "" : " not") + " running");

    return isServiceFound;

}

1
Но имейте в виду, что указанная вами ссылка гласит: «Этот метод предназначен только для отладки или создания пользовательского интерфейса управления процессами».
joe_deniable

getRunningTasks теперь устарела.
Ади

5

Существует гораздо более простой способ, чем все вышеперечисленное, и этот подход не требует использования android.permission.GET_TASKSв манифесте, или не имеет проблемы условий гонки или утечек памяти, указанных в принятом ответе.

  1. Создайте переменную STATIC в основной Деятельности. Статический позволяет другим действиям получать данные от другого действия. onPause()установите эту переменную false , onResumeи onCreate()установите эту переменную true .

    private static boolean mainActivityIsOpen;
  2. Назначьте методы получения и установки этой переменной.

    public static boolean mainActivityIsOpen() {
        return mainActivityIsOpen;
    }
    
    public static void mainActivityIsOpen(boolean mainActivityIsOpen) {
        DayView.mainActivityIsOpen = mainActivityIsOpen;
    }
  3. А потом из другой деятельности или службы

    if (MainActivity.mainActivityIsOpen() == false)
    {
                    //do something
    }
    else if(MainActivity.mainActivityIsOpen() == true)
    {//or just else. . . ( or else if, does't matter)
            //do something
    }

3
Вы говорите, что использование методов доступа лучше, чем использование необработанных открытых статических переменных?
Игорь Ганапольский

1
В Java лучше использовать сеттеры и геттеры, чтобы ваши переменные были приватными. Тем не менее, я считаю, что в Android это общедоступный доступ к общедоступным переменным ...
Стивен

11
Не имеет смысла иметь открытый сеттер, поскольку состояние активности должно обрабатываться только самим действием. Вы должны придерживаться соглашений об именах Java: isActivityOpen будет правильным методом получения. Также использование if boolean == true является избыточным. Кроме того, делегирование государственного управления на деятельность является лучшим подходом.
Лисандро

8
вот почему вы должны были прилежнее посещать ваши курсы @coolcool;)
Джерек TheSith

1
А что если у вас есть несколько запущенных экземпляров активности?
nickmartens1980

5
if(!activity.isFinishing() && !activity.isDestroyed())

Из официальных документов:

Занятие isFinishing ()

Проверьте, находится ли это действие в процессе завершения, потому что вы вызвали на нем метод finish () или кто-то еще запросил его завершение. Это часто используется в onPause (), чтобы определить, просто ли действие приостанавливается или полностью завершается.

Занятие isDestroyed ()

Возвращает true, если последний вызов onDestroy () был сделан для Activity, поэтому этот экземпляр теперь мертв.


4

спасибо ккуди! Я смог адаптировать ваш ответ для работы для деятельности ... вот что сработало в моем приложении ...

public boolean isServiceRunning() { 

ActivityManager activityManager = (ActivityManager)Monitor.this.getSystemService (Context.ACTIVITY_SERVICE); 
    List<RunningTaskInfo> services = activityManager.getRunningTasks(Integer.MAX_VALUE); 
    isServiceFound = false; 
    for (int i = 0; i < services.size(); i++) { 
        if (services.get(i).topActivity.toString().equalsIgnoreCase("ComponentInfo{com.lyo.AutoMessage/com.lyo.AutoMessage.TextLogList}")) {
            isServiceFound = true;
        }
    } 
    return isServiceFound; 
} 

этот пример даст вам true или false, если topActivity соответствует тому, что делает пользователь. Поэтому, если активность, которую вы проверяете, не отображается (то есть включена), вы не получите совпадения. Кроме того, для этого вам нужно добавить разрешение в манифест.

<uses-permission  android:name="android.permission.GET_TASKS"/>

Я надеюсь, что это было полезно!


1
Это разрешение на использование устарело на уровне API 21. Developer.android.com/reference/android/…
Гай Уэст,

2
Понизьте ответ, потому что для доступа к верхней активности (services [i] .topActivity) мы используем минимальный уровень API Q. Ниже, который не будет работать.
Дебашиш Гош

4

Я думаю, что принятый ответ - ужасный способ справиться с этим.

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

@protected
void doSomething() {
}

и переопределить его в производном классе.

Когда событие происходит, просто вызовите этот метод в базовом классе. Правильный «активный» класс будет обрабатывать это тогда. Сам класс затем может проверить, если это не так Paused().

Еще лучше использовать шину событий, такую ​​как GreenRobot , Square , но она устарела и предлагает использовать RxJava


2

Я использовал чек, if (!a.isFinishing())и он, кажется, делает то, что мне нужно. aэто экземпляр активности. Это неверно? Почему никто не попробовал это?


2

что о activity.isFinishing()


Это не очень хорошее решение, так как isFinishing указывает, есть ли активность в процессе убийства.
VelocityPulse

2

ActivityLifecycleCallbacks - отличный способ отслеживать все действия в приложении:

public class BaseActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {

private ActivityState homeState, contentState;

@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.CREATED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.CREATED;
    }
}

@Override
public void onActivityStarted(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.STARTED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.STARTED;
    }
}

@Override
public void onActivityResumed(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.RESUMED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.RESUMED;
    }
}

@Override
public void onActivityPaused(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.PAUSED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.PAUSED;
    }
}

@Override
public void onActivityStopped(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.STOPPED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.STOPPED;
    }
}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}

@Override
public void onActivityDestroyed(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.DESTROYED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.DESTROYED;
    }
}

public ActivityState getHomeState() {
    return homeState;
}

public ActivityState getContentState() {
    return contentState;
}
}

ActivityState:

public enum ActivityState {
    CREATED, STARTED, RESUMED, PAUSED, STOPPED, DESTROYED;
}

Расширьте класс Application и предоставьте его ссылку в файле Android Manifest:

import android.app.Application;

public final class BaseApplication extends Application {
private BaseActivityLifecycleCallbacks baseALC;

@Override
public void onCreate() {
    super.onCreate();
    baseALC = new BaseActivityLifecycleCallbacks();
    this.registerActivityLifecycleCallbacks(baseALC);

}

public BaseActivityLifecycleCallbacks getBaseALC() {
    return baseALC;
}
}

Нажмите в любом месте активность для статуса другой активности:

private void checkAndLaunchHomeScreen() {
    Application application = getApplication();
    if (application instanceof BaseApplication) {
        BaseApplication baseApplication = (BaseApplication) application;
        if (baseApplication.getBaseALC().getHomeState() == null || baseApplication.getBaseALC().getHomeState() == ActivityState.DESTROYED) {
            //Do anything you want
        }
    }
}

https://developer.android.com/reference/android/app/Application.ActivityLifecycleCallbacks.html


1

Не уверен, что это «правильный» способ «делать вещи».
Если нет API-способа решения вопроса (или), чем вы должны немного подумать, возможно, вы делаете что-то неправильно и вместо этого читаете больше документов и т. Д.
(Как я понял, статические переменные - это, как правило, неправильный путь в Android. это может сработать, но определенно будут случаи, когда он не будет работать [например, на производстве, на миллионах устройств]).
Именно в вашем случае я предлагаю подумать, зачем вам знать, живо ли другое действие? .. Вы можете запустить другое действие для результата, чтобы получить его функциональность. Или вы можете получить класс, чтобы получить его функциональность и так далее.
Наилучшие пожелания.


1

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


1

Используйте заказанную трансляцию. См. Http://android-developers.blogspot.nl/2011/01/processing-ordered-broadcasts.html.

В своей деятельности зарегистрируйте получателя в onStart, отмените регистрацию в onStop. Теперь, когда, например, службе необходимо обработать что-то, что активность может сделать лучше, отправьте заказанную рассылку из службы (с обработчиком по умолчанию в самой службе). Теперь вы можете отвечать в действии, когда оно выполняется. Служба может проверить данные результата, чтобы увидеть, была ли обработана широковещательная рассылка, и если нет, предпринять соответствующие действия.


1

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

class MyActivity extends Activity {

     static int activeInstances = 0;

     static boolean isActive() {
        return (activeInstance > 0)
     }

      @Override
      public void onStart() {
         super.onStart();
         activeInstances++;
      } 

      @Override
      public void onStop() {
         super.onStop();
         activeInstances--;
      }
}

отсутствует "s" и "; (точка с запятой)" в обратной строке.
Ali_dev


0

Нашел легкий обходной путь с помощью следующего кода

@Override 
protected void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { 
                // Activity is being brought to front and not being  created again, 
                // Thus finishing this activity will bring the last viewed activity to foreground
                finish(); 
            } 
    }

0

Используйте переменную isActivity, чтобы проверить, активна ли активность или нет.

private boolean activityState = true;

 @Override
protected void onDestroy() {
    super.onDestroy();
    activityState = false;
}

Тогда проверь

if(activityState){
//add your code
}

0

Если вы хотите проверить, находится ли активность в заднем стеке, просто выполните следующие шаги. 1. Объявлен ArrayList в вашем классе приложения [Класс приложения определен в вашем файле mainfest в теге приложения]

private ArrayList<Class> runningActivities = new ArrayList<>();
  1. И добавьте следующие открытые методы для доступа и изменения этого списка.

    public void addActivityToRunningActivityies (Class cls) {
    if (!runningActivities.contains(cls)) runningActivities.add(cls);
    }
    
    public void removeActivityFromRunningActivities (Class cls) {
    if (runningActivities.contains(cls)) runningActivities.remove(cls);
    }
    
    public boolean isActivityInBackStack (Class cls) {
    return runningActivities.contains(cls);
    }
  2. В BaseActivity, где все действия расширяют его, переопределите методы onCreate и onDestroy, чтобы вы могли добавлять и удалять действия из заднего стека следующим образом.

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    ((MyApplicationClass)getApplication()).addActivityToRunningActivityies
    (this.getClass());
    }
    
    @Override
    protected void onDestroy() {
    super.onDestroy();
    
    ((MyApplicationClass)getApplication()).removeActivityFromRunningActivities
    (this.getClass());
    }
  3. Наконец, если вы хотите проверить, находится ли действие в заднем стеке или нет, просто вызовите эту функцию isActivityInBackStack.

Пример: я хочу проверить, находится ли HomeActivity в заднем стеке или нет:

if (((MyApplicationClass) 
getApplication()).isActivityInBackStack(HomeActivity.class)) {
       // Activity is in the back stack
    } else {
       // Activity is not in the back stack
    }


-1

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

public static boolean ativo = false;
public static int counter = 0;

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

@Override
protected void onStart() {
    super.onStart();
    ativo = true;
}

@Override
protected void onStop() {
    super.onStop();
    if (counter==1) ativo = false;
}

@Override
protected void onDestroy() {
    counter--;
    super.onDestroy();
}

Это работает для меня с несколькими действиями, открытыми одновременно.

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