Android - как часто обновлять виджет, но только когда он виден? - PullRequest
30 голосов
/ 10 марта 2010

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

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

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

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

Ответы [ 4 ]

17 голосов
/ 10 марта 2010

Чтобы не обновлять информацию при выключенном экране, используйте 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

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

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

6 голосов
/ 30 мая 2010

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

    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.

0 голосов
/ 07 сентября 2014

Принятый ответ от 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 для обработки относительно дорогой работы, которая включает постоянное сетевое соединение. Это необходимо для мониторинга состояния удаленного сервиса в режиме реального времени.
...