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
Хтось вказував на це, що .. Перевагу слід надавати перевагу статичній змінній через проблеми з витоком пам'яті.
Айуш Гоял

13
Що робити, якщо працюють різні заняття одного класу? Що робити , якщо ви розширюєте MyActivityз MyChildactivityі хочете перевірити , якщо дитина активна?
Містер Сміт

2
Залежно від вашого визначення поняття "біг", ви можете змінити стан змінної в onResume і onPause ....
G. Blake Meike

5
Це рішення взагалі не є хорошим рішенням. Скажімо, ваша активність викликає фрагмент, наприклад, фрагмент буде над активністю, але активність не викличе OnPause, і якщо ви закриєте фрагмент onStop, onStart або будь-які інші методи життєвого циклу, також не буде викликано. Найкраще рішення - перевірити у своєму додатку клас видимості, як описано тут: stackoverflow.com/questions/18038399/…
portfoliobuilder

6
Якщо ви порекомендуєте статику, ви отримаєте -1 від мене
Матей Суїка

52

Я усвідомлюю, що це питання досить старе, але я думаю, що все-таки варто поділитися своїм рішенням, оскільки воно може бути корисним для інших.

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

Активність принаймні частково помітна

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

Діяльність на першому плані

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

3
getLifecycle (). getCurrentState (). isAtLeast (Lifecycle.State.RESUMED)
Radhey

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

Як я можу викликати цю функцію?
Бехзад

1
як завжди, чи є метод, який ви можете викликати всередині свого класу як "функцію", вам потрібен приклад?
Ксеніоне

10
Від developer.android.com/reference/android/app/… "Це ніколи не слід використовувати для основної логіки в додатку, наприклад, для прийняття рішень між різними способами поведінки на основі знайденої тут інформації. Таке використання не підтримується і, ймовірно, порушиться у майбутньому."
joe_deniable

15
Станом на рівень 21 інтерфейсу API (Android 5.0 Lollipop) цей метод застарів.
AxeEffect

30

Варіант без використання допоміжної змінної:

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

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

Значення, що повертається цим виразом, змінюється в onStart () / onStop (), які є подіями, які починаються / зупиняються, показуючи макет діяльності в телефоні.


16
чому б не використовувати jsut 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/…
Віталій Дмитрієв

21

Набагато кращий спосіб, ніж використання статичної змінної та дотримання OOP

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 тут також


Дякую. Але чи потрібен він і брато?

1
Це залежить від того, що ви розумієте під активними. Згідно з моїм кодом, активність знаходиться в стеці, тоді вона активна. А якщо ви хочете обробити видиме чи ні, тоді ви можете скористатися onResume
Zar E Ahmer

19
Це порушується, коли діяльність вбивається без дзвінкаonStop()
Марсель Бро

3
Що станеться, якщо додаток вийде з ладу?
ucMedia

1
Це дуже небезпечне «рішення».
Фірцен

9

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

Змініть константи.PACKAGE та Constannts.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 в основному Activity. Статичний дозволяє іншим операціям отримувати дані від іншої діяльності. onPause()встановити цю змінну БРЕХНЯ , onResumeі onCreate()встановити цю змінну вірно .

    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
Ви хочете сказати, що використання методів accessor краще, ніж використання необмежених загальнодоступних статичних змінних?
ІгорГанапольський

1
У Java краще використовувати сеттери та геттери, щоб зберегти свої змінні приватними. Однак я вважаю, що в Android звичайний доступ до публічних змінних безпосередньо ...
Stephen

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

8
саме тому ви повинні старанно відвідувати ваші курси @coolcool;)
Jerec TheSith

1
А що робити, якщо у вас є кілька примірників запущеної діяльності?
nickmartens1980

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

З офіційних документів:

Діяльність # isFinishing ()

Перевірте, чи ця діяльність закінчується, або тому, що ви викликали на ній закінчення () або хтось інший просив його завершити. Це часто використовується в OnPause (), щоб визначити, чи просто діяльність призупиняється або повністю закінчується.

Активність # isDestroyed ()

Повертає істину, якщо остаточний виклик onDestroy () був здійснений у розділі "Активність", тому цей примірник тепер мертвий.


4

дякую kkudi! Я зміг адаптувати вашу відповідь для роботи для діяльності ... ось, що працювало в моєму додатку ..

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; 
} 

цей приклад дасть вам справжню чи хибну, якщо topActivity відповідає тому, що робить користувач. Отже, якщо активність, на яку ви перевіряєте, не відображається (тобто onPause), ви не отримаєте збіг. Також для цього вам потрібно додати дозвіл у свій маніфест ..

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

Я сподіваюся, що це було корисно!


1
Цей дозвіл на використання було знято на рівні 21 API. Developer.android.com/reference/android/…
Гай Вест,

2
Запропонуємо відповісти, щоб отримати доступ до найвищої активності (служби [i] .topActivity), ми застосовуємо рівень API Q. Нижче це не працює.
Debasish Ghosh

4

Я думаю, що прийнята відповідь - це жахливий спосіб вирішення цього питання.

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

@protected
void doSomething() {
}

і переосмислити його у похідному класі.

Коли подія відбувається, просто зателефонуйте цьому методу в базовий клас. Правильний "активний" клас буде потім обробляти його. Потім сам клас може перевірити, чи ніPaused() .

А ще краще використовувати шину подій на зразок GreenRobot's , Square's , але ця застаріла і пропонує використовувати RxJava


2

Я використав чек if (!a.isFinishing()) і, здається, зробив те, що мені потрібно. a- це екземпляр діяльності. Це неправильно? Чому ніхто не спробував цього?


2

а як на рахунок activity.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;
}
}

Діяльність держави:

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

Розгорніть клас програми та надайте його посилання у файлі 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

Якщо вас цікавить стан життєвого циклу конкретного екземпляра діяльності, рішення siliconeagle виглядає правильним, за винятком того, що нова "активна" змінна повинна бути змінною екземпляра, а не статичною.


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 у вашому класі Application [Клас програми визначено у вашому файлі 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.