Android - как обновлять виджет часто, но только когда он виден?

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

Однако нет необходимости обновлять виджет, если он в настоящее время невидим, что означает:

  • экран выключен
  • другое приложение работает
  • виджет помещается на другую (невидимую) вкладку главного экрана

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


person tomash    schedule 10.03.2010    source источник


Ответы (4)


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

Два других пункта, указанных в вашем вопросе, невозможны. Невозможно определить, находится ли ваш виджет на главном экране, который в настоящее время не отображается, и нет способа определить, работает ли приложение, которое скрывает домашний экран. Я подал заявку на http://b.android.com с просьбой добавить эту функцию в Android. Если вам захочется поставить его в главной роли, это поможет ему получить приоритет: http://code.google.com/p/android/issues/detail?id=5529&q=reporter:mark.r.baird&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

person Mark B    schedule 10.03.2010
comment
Я снялся, по крайней мере, я могу, вы ответили на очень многие мои вопросы, и, вероятно, сделаю это в будущем. Спасибо. - person Pentium10; 10.03.2010
comment
Помечено, жаль, что он не будет доступен в миллионах используемых в настоящее время hasset ... - person tomash; 10.03.2010
comment
Можно определить, какое приложение в настоящее время запущено: ActivityManager mAM = (ActivityManager) context.getSystemService (Context.ACTIVITY_SERVICE); Список ‹RunningTaskInfo› задач = mAM.getRunningTasks (1); - person Niels; 16.06.2012
comment
Зачем вам нужен будильник. Вы получаете это бесплатно из метаданных виджета. Вы можете изменить атрибут updatePeriodMillis, чтобы изменить частоту вызова onUpdate для виджета. См. Документ: developer.android.com/guide/topics/appwidgets/ - person catalyst294; 30.03.2014
comment
@ rmmcnulty9 Пожалуйста, прочтите документацию, на которую вы ссылаетесь: если устройство находится в спящем режиме, когда пришло время для обновления (как определено updatePeriodMillis), то устройство выйдет из спящего режима, чтобы выполнить обновление. Если вы не обновляете чаще одного раза в час, это, вероятно, не вызовет серьезных проблем с временем автономной работы. Однако, если вам нужно обновлять чаще и / или вам не нужно обновлять, пока устройство находится в спящем режиме, вы можете вместо этого выполнять обновления на основе сигнала тревоги, который не разбудит устройство. - person Mark B; 31.03.2014
comment
Ссылка code.google.com недавно была помечена как устаревшая. Означает ли это, что это можно сделать уже сегодня? - person htafoya; 23.04.2015
comment
@htafoya нет, это, вероятно, означает, что какому-то парню из Google была поручена генеральная уборка системы отслеживания проблем, и он закрыл эту задачу вместе с 535 другими 15 марта: code.google.com/p/android/issues/ - person Nilzor; 06.05.2015
comment
@ Catalyst294 Проблема с этим подходом заключается в том, что минимальное значение updatePeriodMillis составляет 30 минут, а некоторым виджетам требуются меньшие интервалы для обновлений. - person Ahmed Korany; 22.01.2019

  1. Вы можете спросить PowerManager об isScreenOn ()
  2. Вы можете зарегистрироваться для намерения ACTION_SCREEN_OFF / ACTION_SCREEN_ON и соответственно включить / выключить таймер.

Хотя приведенный выше ответ относительно AlarmManager верен, этого может быть недостаточно, поскольку я наблюдал, что многие телефоны также доставляют сигналы тревоги, даже если они не относятся к типу * _WAKEUP. Это может произойти, если установлены другие приложения, которые выводят устройство из спящего режима. И если он однажды проснулся, он доставляет все ожидающие тревоги.

person jom    schedule 21.01.2011
comment
Это очень важный момент. Тревога может сработать, даже если экран спит, как описано в эту ветку. - person lseidman; 22.02.2013
comment
Я также заметил, что при включенном режиме разработчика (и записи содержимого в logcat) устройство не спит. Чтобы проверить, что он будет делать без режима разработчика, я добавил счетчик для всех обновлений, отображаемых в виджете, и заметил, что при выключенном режиме разработчика он перейдет в спящий режим и не будет обновлять виджет событиями AlarmManager.RTC. Я не могу найти никакой документации, чтобы увидеть, что режим разработчика не дает ему уснуть, но для меня это имеет смысл. - person Renso Lohuis; 27.10.2014

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

    ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);

    List<RunningTaskInfo> runningTasks = am.getRunningTasks(2);
    for (RunningTaskInfo t : runningTasks) {
        if (t != null && t.numRunning > 0) {
            ComponentName cn = t.baseActivity;
            if (cn == null) continue;

            String clz = cn.getClassName();
            String pkg = cn.getPackageName();

            // TODO make this configurable
            if (pkg != null && pkg.startsWith("com.android.launcher")) {
                return true;
            }

            return false;
        }
    }

Возможно, это ответ на ваше требование №2. Хотя это может не работать под другими сторонними программами запуска.

== Обновление ==

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

person xandy    schedule 30.05.2010
comment
Неужели это ужасно не работает при работе на нестандартном рабочем столе? - person Adrian; 12.01.2011
comment
Пожалуйста, посмотрите мой обновленный ответ, у меня есть лучший метод, который должен работать с третьими сторонами. - person xandy; 12.01.2011

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

Между тем, это все еще реальная проблема для некоторых типов виджетов. jom представил возможность регистрации для получения намерений ACTION_SCREEN_OFF / ACTION_SCREEN_ON. Это полезно, потому что недостаточно полагаться на повторяющийся сигнал тревоги, не связанный с пробуждением, поскольку другие службы вызывают пробуждение. Это сложно, потому что на такие действия нельзя подписаться через AndroidManifest.xml, а AppWidgetProvider не разрешено вызывать context.registerReceiver(). Эти проблемы обсуждаются в нескольких других вопросах StackOverflow, включая Прослушивание ACTION_SCREEN_OFF, android.intent.action.SCREEN_ON не не работает как фильтр намерений получателя и Android - как получить намерения трансляции ACTION_SCREEN_ON / OFF?.

Мне удалось подписаться на намерения ACTION_SCREEN_OFF / ACTION_SCREEN_ON в виджете, создав дочерний экземпляр BroascastReceiver и используя context.getApplicationContext().registerReceiver() для его регистрации. Это вполне могло быть обманом и, по крайней мере, в некоторых последующих версиях Android, может произойти сбой на этапе регистрации или, возможно, события просто не будут доставлены. Я написал код для обработки этих случаев, но пока это работает. К сожалению, конечно, это не сработает, если и когда приложение когда-либо будет убито.

Другая возможность - использовать метод типа isHomeScreenShowing(), как описано здесь, на который ссылается ответ xandy. Идеи там, вероятно, можно было бы оптимизировать, кэшируя сгенерированный список установленных CATEGORY_HOME приложений и прослушивая широковещательные сообщения ACTION_PACKAGE_ADDED / CHANGED / REMOVED для его обновления.

Моя стратегия:

  • Старайтесь не звонить (через повторяющийся сигнал), когда вас не видно.
  • При вызове проверьте состояние экрана и другие индикаторы видимости, прежде чем делать что-нибудь дорогостоящее.
  • Только после этого вызывайте IntentService для выполнения относительно дорогостоящей работы, которая включает постоянное сетевое соединение. Это необходимо для отслеживания состояния удаленной службы почти в реальном времени.
person awy    schedule 07.09.2014