Nano Hash - криптовалюты, майнинг, программирование

Android: как я могу получить текущую активность переднего плана (из службы)?

Есть ли собственный способ Android получить ссылку на текущую активность из службы?

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



Ответы:


1

Есть ли собственный способ Android получить ссылку на текущую активность из службы?

Вы не можете быть владельцем «текущего действия».

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

  1. Отправьте трансляцию Intent к мероприятию - вот пример проекта демонстрация этого паттерна
  2. Попросите действие предоставить PendingIntent (например, через createPendingResult()), который вызывает служба.
  3. Попросите действие зарегистрировать объект обратного вызова или прослушивателя в службе через bindService(), а служба вызовет метод события для этого объекта обратного вызова / прослушивателя.
  4. Отправьте заказанную трансляцию Intent активности с низким приоритетом BroadcastReceiver в качестве резервной копии (чтобы поднять Notification, если действие не отображается на экране) - вот сообщение в блоге с дополнительной информацией об этом шаблоне
06.10.2010
  • Спасибо, но поскольку у меня есть множество действий, и я не хочу их все обновлять, я искал способ Android получить foregroundActivity. Как вы говорите, я не смогу этого сделать. Значит, я должен обойти это. 07.10.2010
  • @ Джордж: То, что ты хочешь, в любом случае тебе не поможет. Как вы отметили, у вас множество занятий. Следовательно, все это отдельные классы. Следовательно, ваша служба ничего не сможет сделать с ними без массивного if-блока instanceof проверок или без рефакторинга действий для совместного использования общего суперкласса или интерфейса. И если вы собираетесь реорганизовать действия, вы также можете сделать это так, чтобы это лучше соответствовало структуре и охватило больше сценариев, например, когда ни одно из ваших действий неактивно. №4, вероятно, наименее трудоемкий и самый гибкий. 07.10.2010
  • Спасибо, но у меня есть решение получше. Все мои действия расширяют настраиваемый класс BaseActivity. Я установил ContextRegister, который регистрирует активность как текущую, когда она находится на переднем плане, с тремя строками в моем классе BaseActivity. Тем не менее, спасибо за поддержку. 08.10.2010
  • @ Джордж: Остерегайтесь утечек памяти. В Java по возможности следует избегать изменяемых статических элементов данных. 08.10.2010
  • Я плотно заключил объект в оболочку, хотя действительно буду иметь это в виду. Спасибо. 08.10.2010

  • 2

    Обновление: этот больше не работает с действиями других приложений, начиная с Android 5.0


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

    Пример здесь

    Есть простой способ получить список запущенных задач из службы ActivityManager. Вы можете запросить максимальное количество задач, запущенных на телефоне, и по умолчанию текущая активная задача возвращается первой.

    Получив это, вы можете получить объект ComponentName, запросив topActivity из своего списка.

    Вот пример.

        ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        Log.d("topActivity", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName());
        ComponentName componentInfo = taskInfo.get(0).topActivity;
        componentInfo.getPackageName();
    

    Вам понадобится следующее разрешение для вашего манифеста:

    <uses-permission android:name="android.permission.GET_TASKS"/>
    
    20.01.2011
  • Ваш ответ на 100% правильный. Спасибо xxx 4. Лучше, чтобы вы разместили тот же ответ здесь. 28.04.2012
  • Будет ли это работать даже с возможностью одновременного представления нескольких фрагментов? 07.09.2012
  • @ArtOfWarfare не проверял, но да, количество имеющихся у вас фрагментов не имеет значения, поскольку они всегда размещаются в одном действии. 09.09.2012
  • Если мне нужна текущая активность чаще, мне нужно опрашивать очень часто, верно? Есть ли способ получить событие обратного вызова при изменении активности переднего плана? 29.03.2013
  • Просто чтобы все знали, в документации говорится о методе getRunningTasks (). -------- Примечание: этот метод предназначен только для отладки и представления пользовательских интерфейсов управления задачами. Это никогда не должно использоваться для базовой логики в приложении, такой как выбор между различными поведениями на основе информации, найденной здесь. Такое использование не поддерживается и, скорее всего, выйдет из строя в будущем. Например, если несколько приложений могут активно работать одновременно, предположения, сделанные о значении данных здесь для целей потока управления, будут неверными. ------------ 04.07.2013
  • @Ryan Есть ли лучшее решение, чтобы получить текущую активность переднего плана? Спасибо! 07.11.2014
  • полифейк на API 21 As of LOLLIPOP, this method is no longer available to third party applications: the introduction of document-centric recents means it can leak person information to the caller. For backwards compatibility, it will still return a small subset of its data: at least the caller's own tasks, and possibly some other tasks such as home that are known to not be sensitive. 23.12.2014
  • Как получить объект Activity, получив componentInfo.getPackageName();? В случае, если я хочу установить текущую яркость активности в фоновой службе. 30.03.2015
  • @PeterZhu, если вы хотите получить экземпляр Activity, я не думаю, что это возможно из соображений безопасности. Я не понимаю, что вы имеете в виду, говоря об установке яркости активности; возможно, для этого стоит создать новый вопрос StackOverflow. 19.04.2015
  • Есть ли способ добиться максимальной активности в Lollipop? 06.07.2015
  • @ aka_007, да; используйте AccessibilityService. 10.07.2015

  • 3

    Предупреждение: нарушение Google Play

    Google пригрозил удалить приложения из Play Маркета, если они будут использовать службы специальных возможностей в целях, не связанных со специальными возможностями. Однако это, как сообщается, пересматривается.


    Используйте AccessibilityService

    Преимущества

    • Протестировано и работает в Android 2.2 (API 8) через Android 7.1 (API 25).
    • Не требует опроса.
    • Не требует разрешения GET_TASKS.

    Недостатки

    • Каждый пользователь должен включить службу в настройках специальных возможностей Android.
    • Это ненадежно на 100%. Иногда события происходят не по порядку.
    • Служба всегда работает.
    • Когда пользователь пытается включить AccessibilityService, он не может нажать кнопку Кнопка ОК, если приложение разместило на экране оверлей. Некоторые приложения, которые делают это, - это Velis Auto Brightness и Lux. Это может сбивать с толку, потому что пользователь может не знать, почему он не может нажать кнопку или как это обойти.
    • AccessibilityService не будет знать текущую активность до первого изменение деятельности.

    Пример

    Услуга

    public class WindowChangeDetectingService extends AccessibilityService {
    
        @Override
        protected void onServiceConnected() {
            super.onServiceConnected();
    
            //Configure these here for compatibility with API 13 and below.
            AccessibilityServiceInfo config = new AccessibilityServiceInfo();
            config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
            config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
    
            if (Build.VERSION.SDK_INT >= 16)
                //Just in case this helps
                config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
    
            setServiceInfo(config);
        }
    
        @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {
            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
                if (event.getPackageName() != null && event.getClassName() != null) {
                    ComponentName componentName = new ComponentName(
                        event.getPackageName().toString(),
                        event.getClassName().toString()
                    );
    
                    ActivityInfo activityInfo = tryGetActivity(componentName);
                    boolean isActivity = activityInfo != null;
                    if (isActivity)
                        Log.i("CurrentActivity", componentName.flattenToShortString());
                }
            }
        }
    
        private ActivityInfo tryGetActivity(ComponentName componentName) {
            try {
                return getPackageManager().getActivityInfo(componentName, 0);
            } catch (PackageManager.NameNotFoundException e) {
                return null;
            }
        }
    
        @Override
        public void onInterrupt() {}
    }
    

    AndroidManifest.xml

    Слейте это в свой манифест:

    <application>
        <service
            android:label="@string/accessibility_service_name"
            android:name=".WindowChangeDetectingService"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService"/>
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibilityservice"/>
        </service>
    </application>
    

    Информация о сервисе

    Поместите это в res/xml/accessibilityservice.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <!-- These options MUST be specified here in order for the events to be received on first
     start in Android 4.1.1 -->
    <accessibility-service
        xmlns:tools="http://schemas.android.com/tools"
        android:accessibilityEventTypes="typeWindowStateChanged"
        android:accessibilityFeedbackType="feedbackGeneric"
        android:accessibilityFlags="flagIncludeNotImportantViews"
        android:description="@string/accessibility_service_description"
        xmlns:android="http://schemas.android.com/apk/res/android"
        tools:ignore="UnusedAttribute"/>
    

    Включение службы

    Каждому пользователю приложения потребуется явно включить AccessibilityService, чтобы это будет использоваться. См. этот ответ StackOverflow, чтобы узнать, как это сделать.

    Обратите внимание, что пользователь не сможет нажать кнопку ОК при попытке включить службу специальных возможностей, если приложение разместило на экране оверлей, например Velis Auto Brightness или Lux.

    24.12.2014
  • почему бы не подчеркнуть необходимость включения AccessibilityService в настройках? http://stackoverflow.com/questions/11087758/accessibility-service-is-not-started 01.04.2015
  • @SalutonMondo, я полагаю, я полагаю, что люди, читающие это, будут читать раздел Недостатки, поскольку недостатки очень важны. Но я думаю, ты прав; Я могу представить, как люди бегают по деталям. Я добавил несколько инструкций внизу, чтобы прояснить это требование. 01.04.2015
  • Что именно означает Убедитесь, что вы создали your.app.ServiceSettingsActivity, чтобы вы могли предоставить пользовательский интерфейс пользователям, когда они просматривают службу специальных возможностей в настройках Android. ? 04.06.2015
  • @lovemint, я имел в виду: я указал пример settingsActivity из your.app.ServiceSettingsActivity, поэтому вам следует изменить это на свои собственные настройки для вашей службы специальных возможностей. Я думаю, что действия с настройками в любом случае необязательны, поэтому я удалил эту часть из своего ответа, чтобы упростить его. 04.06.2015
  • Большое спасибо, последний вопрос. Если мне нужно перейти от API 8 к текущему, я должен делать это в коде вместо использования XML? 08.06.2015
  • @lovemint, верно. Я только что обновил пример кода, чтобы сделать это. 09.06.2015
  • @Sam Я могу подтвердить, что эта служба работает отлично. Одно странное поведение, я использовал намерение в основном действии, чтобы включить службу доступности. После этой первой активации служба активируется, но onAccessibilityEvent не получает никаких событий, но если я отключу и снова включу Службу доступности, служба активируется повторно и onAccessibilityEvent начинает работать. 11.06.2015
  • @lovemint, спасибо, что заметили это! Похоже на ошибку в Android 4.1.1. Я просто исправил это, указав конфигурацию службы доступности как в XML-файле, так и в коде. См. Обновленный ответ для примера. 12.06.2015
  • @ Сэм, ты можешь взглянуть на мой вопрос? stackoverflow.com/questions/32157604/ спасибо очень! 24.08.2015
  • Спасибо за ваш код. Я создал для вас это приложение :) 13.08.2016
  • Эй, может ли это быть полезно для получения просмотров самых популярных действий, как в инструменте мониторинга в SDK? Я спросил об этом здесь: stackoverflow.com/q/39315028/878126 15.09.2016
  • @androiddeveloper, я не помню; Прошло много времени с тех пор, как я играл с этим. Я бы посоветовал отрегулировать настройки AccessibilityService, чтобы предоставить ему доступ к как можно большему количеству, а затем поэкспериментировать с ним, чтобы увидеть, предоставляет ли он то, что вы ищете. 15.09.2016
  • @Sam Я нашел этот образец: github.com/seguri/GetForegroundActivity. Кажется, работает хорошо. Я хотел бы спросить вас, знаете ли вы, как получить информацию о просмотрах активности вверху. 16.09.2016
  • Я не знаю, как правильно перезапустить его программно, если вы его остановили. - на самом деле вы можете отключить и включить его по своему желанию, например: stackoverflow.com/a/5625179/878126 16.09.2016
  • @androiddeveloper: 1. На этот образец уже есть ссылка 3 комментария над вашим комментарием, и образец основан на коде в этом ответе. :) 16.09.2016
  • @androiddeveloper: 2. Относительно получения информации о просмотре основной активности см. мой последний ответ вам. 16.09.2016
  • @androiddeveloper: 3. Что касается программного запуска AccessibilityService, я имел в виду его фактический запуск, как в startService, а не включение. Насколько я помню, повторное включение программно остановленного AccessibilityService программным способом не запускало службу, когда я последний раз это тестировал. 16.09.2016
  • @Sam Использование disable & enable работает нормально. Что касается информации о просмотре, если вы что-то найдете, напишите об этом в посте, о котором я писал. 18.09.2016
  • @androiddeveloper, я просто потратил некоторое время на то, чтобы пробовать несколько техник для программного запуска и остановки службы, и мне не удалось заставить вашу технику отключения и включения работать. Не могли бы вы рассказать, как вы это сделали? Я разместил здесь вопрос по этому поводу: stackoverflow.com/questions/40433449/ 05.11.2016
  • @Sam В настоящее время он просто проверяет изменение состояния окна. Моя проблема заключается в том, чтобы проверить, какое действие или приложение открыто в настоящее время, и у меня есть собственная клавиатура. Поэтому каждый раз, когда я открываю клавиатуру в другом приложении, она показывает, что это мое приложение, а не другое приложение. Любое решение по этому поводу? 20.09.2017
  • @JimitPatel, он фактически проверяет как состояние окна, так и то, является ли текущее окно активным. Вы используете проверку isActivity из моего примера кода? Я только что проверил и не понимаю описанной вами проблемы. 20.09.2017
  • @ Sam, круто, работает ... Я напортачил с другой частью кода. Спасибо :) 20.09.2017
  • Скажем, я нашел это приложение: play.google .com / store / apps /, и в нем говорится, что рекомендуется использовать разрешение статистики использования вместо доступности. Как могло быть лучше? Я не могу найти для этого слушателя. Только опрос текущего состояния. 14.06.2020
  • @androiddeveloper, см. раздел «Недостатки» в моем ответе. Служба доступности обычно работает хорошо, но иногда события, помимо других проблем, происходят не по порядку. Опрос практически на 100% надежен. Я переключился на статистику использования в своем приложении в производственной среде, и с тех пор у меня не было никаких проблем. 15.06.2020
  • @Sam Почему они вышли из строя? Вы можете воспроизвести это? Похоже на ошибку 15.06.2020
  • @androiddeveloper, это одна из многих ошибок в Android :) Насколько я помню, это связано со временем, поэтому не может быть надежно воспроизведено. Потребовались месяцы, чтобы увидеть это в действии. 15.06.2020
  • @Sam Может быть, вам стоит сообщить об этом, тогда: Issueetracker.google.com/issues 15.06.2020

  • 4

    Это можно сделать:

    1. Реализуйте свой собственный класс приложения, зарегистрируйтесь в ActivityLifecycleCallbacks - так вы сможете увидеть, что происходит с нашим приложением. При каждом возобновлении обратный вызов назначает текущую видимую активность на экране, а при паузе удаляет назначение. Он использует метод registerActivityLifecycleCallbacks(), который был добавлен в API 14.

      public class App extends Application {
      
      private Activity activeActivity;
      
      @Override
      public void onCreate() {
          super.onCreate();
          setupActivityListener();
      }
      
      private void setupActivityListener() {
      registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
              @Override
              public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
              }
              @Override
              public void onActivityStarted(Activity activity) {
              }
              @Override
              public void onActivityResumed(Activity activity) {
                  activeActivity = activity;
              }
              @Override
              public void onActivityPaused(Activity activity) {
                  activeActivity = null;
              }
              @Override
              public void onActivityStopped(Activity activity) {
              }
              @Override
              public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
              }
              @Override
              public void onActivityDestroyed(Activity activity) {
              }
          });
      }
      
      public Activity getActiveActivity(){
          return activeActivity;
      }
      
      }
      
    2. В вашем сервисе вызовите getApplication() и приведите его к имени вашего класса приложения (в данном случае App). Затем вы можете вызвать app.getActiveActivity() - это даст вам текущее видимое действие (или null, если активность не видна). Вы можете получить название Activity, позвонив activeActivity.getClass().getSimpleName()

    27.11.2016
  • Я получаю исключение Nullpointer в activeActivity.getClass (). GetSimpleName (). Не могли бы вы помочь 01.06.2017
  • Как вы можете видеть из ActivityLifecycleCallbacks - в случае, если активность не отображается, application.getActiveActivity () возвращает null. Это означает, что никакой активности не видно. Вам необходимо проверить это в своем сервисе или где-либо еще, где вы это используете. 02.06.2017
  • хорошо .. но в случае возобновления деятельности это не должно возвращать null ?? Моя деятельность началась, и в ее резюме я получил так 02.06.2017
  • Трудно догадаться, попробуйте поставить точки останова на onActivityResumed(), onActivityPaused() и getActiveActivity(), чтобы увидеть, как это называется, если вообще так. 03.06.2017
  • @beginner необходимо проверить, совпадают ли activity и activeActivity, прежде чем назначать activeActivity с null, чтобы избежать ошибок из-за смешанного порядка вызова методов жизненного цикла различных действий. 25.01.2018
  • Этот подход работает нормально, НО, если у вас есть действия в заднем стеке, то вы изменили ориентацию устройства, getActiveActivity () всегда будет возвращать активность в фоновом режиме, а не видимую. Кто-нибудь знает, как решить эту проблему? 10.07.2018

  • 5

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

    public interface ContextProvider {
        Context getActivityContext();
    }
    
    public class MyApplication extends Application implements ContextProvider {
        private Activity currentActivity;
    
        @Override
        public Context getActivityContext() {
             return currentActivity;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                    MyApplication.this.currentActivity = activity;
                }
    
                @Override
                public void onActivityStarted(Activity activity) {
                    MyApplication.this.currentActivity = activity;
                }
    
                @Override
                public void onActivityResumed(Activity activity) {
                    MyApplication.this.currentActivity = activity;
                }
    
                @Override
                public void onActivityPaused(Activity activity) {
                    MyApplication.this.currentActivity = null;
                }
    
                @Override
                public void onActivityStopped(Activity activity) {
                    // don't clear current activity because activity may get stopped after
                    // the new activity is resumed
                }
    
                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    
                }
    
                @Override
                public void onActivityDestroyed(Activity activity) {
                    // don't clear current activity because activity may get destroyed after
                    // the new activity is resumed
                }
            });
        }
    }
    

    Затем настройте контейнер DI для возврата экземпляра MyApplication для ContextProvider, например.

    public class ApplicationModule extends AbstractModule {    
        @Provides
        ContextProvider provideMainActivity() {
            return MyApplication.getCurrent();
        }
    }
    

    (Обратите внимание, что реализация getCurrent() в приведенном выше коде опущена. Это просто статическая переменная, которая устанавливается из конструктора приложения)

    29.07.2016
  • необходимо проверить, совпадают ли activity и currentActivity перед назначением currentActivity с null, чтобы избежать ошибок из-за смешанного порядка вызова методов жизненного цикла различных действий. 25.01.2018

  • 6

    Используйте ActivityManager.

    Если вы хотите знать только приложение, содержащее текущее действие, вы можете сделать это с помощью _ 2_. Методика, которую вы можете использовать, зависит от версии Android:

    Преимущества

    • Должен работать во всех современных версиях Android.

    Недостатки

    • Не работает в Android 5.1+ (возвращает только ваше собственное приложение)
    • В документации для этих API говорится, что они предназначен только для отладки и управления пользовательскими интерфейсами.
    • Если вам нужны обновления в реальном времени, вам нужно использовать опрос.
    • Использует скрытый API: ActivityManager.RunningAppProcessInfo.processState
    • Эта реализация не отслеживает активность переключателя приложений.

    Пример (на основе кода KNaito)

    public class CurrentApplicationPackageRetriever {
    
        private final Context context;
    
        public CurrentApplicationPackageRetriever(Context context) {
            this.context = context;
        }
    
        public String get() {
            if (Build.VERSION.SDK_INT < 21)
                return getPreLollipop();
            else
                return getLollipop();
        }
    
        private String getPreLollipop() {
            @SuppressWarnings("deprecation")
            List<ActivityManager.RunningTaskInfo> tasks =
                activityManager().getRunningTasks(1);
            ActivityManager.RunningTaskInfo currentTask = tasks.get(0);
            ComponentName currentActivity = currentTask.topActivity;
            return currentActivity.getPackageName();
        }
    
        private String getLollipop() {
            final int PROCESS_STATE_TOP = 2;
    
            try {
                Field processStateField = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
    
                List<ActivityManager.RunningAppProcessInfo> processes =
                    activityManager().getRunningAppProcesses();
                for (ActivityManager.RunningAppProcessInfo process : processes) {
                    if (
                        // Filters out most non-activity processes
                        process.importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                        &&
                        // Filters out processes that are just being
                        // _used_ by the process with the activity
                        process.importanceReasonCode == 0
                    ) {
                        int state = processStateField.getInt(process);
    
                        if (state == PROCESS_STATE_TOP) {
                            String[] processNameParts = process.processName.split(":");
                            String packageName = processNameParts[0];
    
                            /*
                             If multiple candidate processes can get here,
                             it's most likely that apps are being switched.
                             The first one provided by the OS seems to be
                             the one being switched to, so we stop here.
                             */
                            return packageName;
                        }
                    }
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
    
            return null;
        }
    
        private ActivityManager activityManager() {
            return (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        }
    
    }
    

    Манифест

    Добавьте разрешение GET_TASKS для AndroidManifest.xml:

    <!--suppress DeprecatedClassUsageInspection -->
    <uses-permission android:name="android.permission.GET_TASKS" />
    
    20.04.2015
  • это больше не работает на Android M. getRunningAppProcesses () теперь возвращает только пакет вашего приложения 03.06.2015
  • Не работает и для уровня API 22 (Android 5.1). Проверено на сборке LPB23 29.01.2016

  • 7

    Я использую это для своих тестов. Однако это API> 19 и только для действий вашего приложения.

    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static Activity getRunningActivity() {
        try {
            Class activityThreadClass = Class.forName("android.app.ActivityThread");
            Object activityThread = activityThreadClass.getMethod("currentActivityThread")
                    .invoke(null);
            Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
            activitiesField.setAccessible(true);
            ArrayMap activities = (ArrayMap) activitiesField.get(activityThread);
            for (Object activityRecord : activities.values()) {
                Class activityRecordClass = activityRecord.getClass();
                Field pausedField = activityRecordClass.getDeclaredField("paused");
                pausedField.setAccessible(true);
                if (!pausedField.getBoolean(activityRecord)) {
                    Field activityField = activityRecordClass.getDeclaredField("activity");
                    activityField.setAccessible(true);
                    return (Activity) activityField.get(activityRecord);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    
        throw new RuntimeException("Didn't find the running activity");
    }
    
    04.10.2015
  • Замените ArrayMap на Map, и он будет работать и на 4.3. Не тестировал более ранние версии Android. 20.01.2016

  • 8

    Используйте этот код для API 21 или выше. Это работает и дает лучший результат по сравнению с другими ответами, он отлично определяет процесс переднего плана.

    if (Build.VERSION.SDK_INT >= 21) {
        String currentApp = null;
        UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
        long time = System.currentTimeMillis();
        List<UsageStats> applist = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time);
        if (applist != null && applist.size() > 0) {
            SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
            for (UsageStats usageStats : applist) {
                mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
    
            }
            if (mySortedMap != null && !mySortedMap.isEmpty()) {
                currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
            }
        }
    
    30.07.2016
  • Не могли бы вы подробнее рассказать, чем результаты этого метода лучше, чем другие ответы? 15.12.2016
  • Работает ли это и с меню уведомлений. Я столкнулся с проблемой, когда мне позвонят или сообщат. UsageStatsManager начинает давать мне имя пакета systemUi вместо моего приложения. 12.03.2019
  • @kukroid, опубликуйте отдельный вопрос и укажите свой исходный код, информацию об устройстве, а также приложения для обмена сообщениями и телефона, которые вы используете. 22.03.2019

  • 9

    Вот что я предлагаю и что сработало для меня. В своем классе приложения реализуйте прослушиватель Application.ActivityLifeCycleCallbacks и установите переменную в своем классе приложения. Затем запросите переменную по мере необходимости.

    class YourApplication: Application.ActivityLifeCycleCallbacks {
        
        var currentActivity: Activity? = null
    
        fun onCreate() {
            registerActivityLifecycleCallbacks(this)
        }
    
        ...
        
        override fun onActivityResumed(activity: Activity) {
            currentActivity = activity
        }
    }
    
    11.08.2020

    10

    Мне нравится идея Application.ActivityLifecycleCallbacks. Но получить максимальную активность может быть непросто.

    • В вашем приложении может быть несколько действий
    • Некоторые действия могут быть уничтожены
    • Некоторые действия могут уйти в фон

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

    Все это объединяется в один вызов getTopForegroundActivity(), который возвращает верхнюю активность переднего плана или null, если в стеке нет действий или их нет на переднем плане.

    использование

    public class MyApp extends Application {
    
        private ActivityTracker activityTracker;
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            activityTracker = new ActivityTracker();
            registerActivityLifecycleCallbacks(activityTracker);
            
            ...
    
            Activity activity = activityTracker.getTopForegroundActivity();
            if(activity != null) {
                // Do something
            }
        }
    }
    

    Источник

    public class ActivityTracker implements Application.ActivityLifecycleCallbacks {
        private final Map<Activity, ActivityData> activities = new HashMap<>();
    
    
        public Activity getTopForegroundActivity() {
            if (activities.isEmpty()) {
                return null;
            }
            ArrayList<ActivityData> list = new ArrayList<>(activities.values());
            Collections.sort(list, (o1, o2) -> {
                int compare = Long.compare(o2.started, o1.started);
                return compare != 0 ? compare : Long.compare(o2.resumed, o1.resumed);
            });
    
            ActivityData topActivity = list.get(0);
            return topActivity.started != -1 ? topActivity.activity : null;
        }
    
    
        @Override
        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
            activities.put(activity, new ActivityData(activity));
        }
    
        @Override
        public void onActivityStarted(@NonNull Activity activity) {
            ActivityData activityData = activities.get(activity);
            if (activityData != null) {
                activityData.started = System.currentTimeMillis();
            }
        }
    
        @Override
        public void onActivityResumed(@NonNull Activity activity) {
            ActivityData activityData = activities.get(activity);
            if (activityData != null) {
                activityData.resumed = System.currentTimeMillis();
            }
        }
    
        @Override
        public void onActivityPaused(@NonNull Activity activity) {
            ActivityData activityData = activities.get(activity);
            if (activityData != null) {
                activityData.resumed = -1;
            }
        }
    
        @Override
        public void onActivityStopped(@NonNull Activity activity) {
            ActivityData activityData = activities.get(activity);
            if (activityData != null) {
                activityData.started = -1;
            }
        }
    
        @Override
        public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
    
        }
    
        @Override
        public void onActivityDestroyed(@NonNull Activity activity) {
            activities.remove(activity);
        }
    
        private static class ActivityData {
    
            public final Activity activity;
            public long started;
            public long resumed;
    
            private ActivityData(Activity activity) {
                this.activity = activity;
            }
        }
    }
    
    21.03.2021

    11

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

    08.03.2017
  • Ищем нативный способ сделать это 11.10.2017

  • 12

    Вот мой ответ, который отлично работает ...

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

    Вот способ. Когда вы запускаете Activity, вы сохраняете это Activity с помощью Application.setCurrentActivity (getIntent ()); Это приложение сохранит его. В своем классе обслуживания вы можете просто сделать как Intent currentIntent = Application.getCurrentActivity (); getApplication (). startActivity (currentIntent);

    26.03.2015
  • Это предполагает, что служба работает в том же процессе, что и Activity, верно? 01.10.2015

  • 13

    Буквально недавно об этом узнал. С apis как:

    • minSdkВерсия 19
    • targetSdkVersion 26

      ActivityManager.getCurrentActivity (контекст)

    Надеюсь, это будет полезно.

    14.03.2018
  • Возникли мои надежды. Возможно, когда на этот вопрос был дан ответ, он существовал, но на данный момент в классе ActivityManager нет функции getCurrentActivity() (developer.android.com/reference/android/app/ActivityManager). Забавно, что эта функция действительно существует: ActivityManager.isUserAMonkey(). 12.05.2018
  • Это определяет, используете ли вы агент тестирования обезьян для проверки своей активности. Несмотря на забавное название, оно может оказаться весьма полезным для тестирования (и рассмешить других, очевидно.) developer.android.com/studio/test/monkeyrunner 08.06.2018
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..