Регулярное обновление значения TextView в виджете Андроида, раз в несколько секунд
Подскажите, пожалуйста, как корректно реализовать обновление (присвоение нового значения) TextView для виджета в Android с интервалом раз в несколько секунд? Встроенный параметр updatePeriodMillis не подходит из-за ограничения обновления виджетов раз в 30 минут. Необходимо чтобы текст в виджете менялся каждые несколько секунд.
Как осуществить эту задачу корректно и оптимально: чтобы минимально расходовать батарею, чтобы обновление по таймеру работало только при видимом виджете на активном и включенном экране, а в остальных случаях (работающее приложение, выключенный или заблокированный экран, открытые настройки и т.п.) - обновления виджета отключались?
Имеется простой NewAppWidget виджет, созданный Android Studio по-умолчанию:
package com.dev.app;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.widget.RemoteViews;
/**
* Implementation of App Widget functionality.
*/
public class NewAppWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
CharSequence widgetText = WidgedDataGenerator.getWidgetString();
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
views.setTextViewText(R.id.appwidget_text, widgetText);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
@Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
}
Новые значения генерируется через WidgedDataGenerator.getWidgetString(). Необходимо, чтобы обновление текста в TextView происходило каждые 2 или 20 секунд (в зависимости от значения в настройках приложения), при этом потребляя минимум ресурсов.
Ответы (2 шт):
Вы можете рассмотреть вариант с использованием UsageStatsManager, через него можно получать статистику использования телефона и в зависимости от неё, включать/выключать обновление виджета.
Но в целом проще использовать (больше информации в сети) вариант с BroadcastReceiver
для перехвата событий включения и выключения экрана, Handler
и Runnable
для обновления виджета.
Следующий код собран из открытых примеров и служит только примерной демонстрацией, возможно в нём содержаться ошибки:
public class ScreenReceiver extends BroadcastReceiver {
private static boolean isScreenOn = false;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
isScreenOn = true;
startWidgetUpdater(context);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
isScreenOn = false;
}
}
public static boolean isScreenOn() {
return isScreenOn;
}
private void startWidgetUpdater(Context context) {
Intent intent = new Intent(context, WidgetUpdaterService.class);
context.startService(intent);
}
}
public class WidgetUpdaterService extends Service {
private static final int UPDATE_INTERVAL = 2000; // 2 секунды
private Handler mHandler = new Handler();
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
if (ScreenReceiver.isScreenOn()) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(getApplicationContext(), NewAppWidget.class));
for (int appWidgetId : appWidgetIds) {
NewAppWidget.updateAppWidget(getApplicationContext(), appWidgetManager, appWidgetId);
}
mHandler.postDelayed(this, UPDATE_INTERVAL);
}
}
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mHandler.post(mRunnable);
}
@Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mRunnable);
}
}
- Регистрируем ресивер и сервис:
<receiver android:name=".ScreenReceiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_ON"/>
<action android:name="android.intent.action.SCREEN_OFF"/>
</intent-filter>
</receiver>
<service android:name=".WidgetUpdaterService"/>
- Добавим запуск сервиса при создании виджета:
public class NewAppWidget extends AppWidgetProvider {
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
context.startService(new Intent(context, WidgetUpdaterService.class));
}
// ...
}
Есть видео на YouTube с вполне рабочим приложением. К сожалению, автор не очень многословен. Но есть ссылка на исходники widget update.
Мне не удалось заставить обновляться виджет каждую секунду, но раз в две секунды он обновляется или около того.
Для обновления виджета используется AlarmManager
.