android - 如何更新 OREO 中的 Widget(AlarmManager 在数小时/数天后停止)

标签 android widget android-widget alarmmanager android-8.0-oreo

我有一个信息小部件,每 60 秒更新一次。在 OREO 之前,我使用服务来完成它,但现在,你不能这样做,因为当应用程序在后台时你不能使用该服务,所以我关注了这里的一些帖子并使用警报和 AlarmManager 来更新小部件.

问题是它工作了几个小时,但是一两天后,警报的onReceive方法就不再被调用了。发生了一些事情,因为警报在用户没有删除小部件的情况下停止了,所以 wiget 停止更新。

AlarmManager 似乎不是执行此操作的最佳方法,或者我做错了什么。

这是我的小部件警报接收器:

public class WidgetAlarmReceiver extends BroadcastReceiver {
    private final static String TAG = "WidgetAlarmReceiver";

    @Override
    public void onReceive(final Context context, Intent intent) {
        Log.d(TAG,"onReceive");

        ComponentName componentName = new ComponentName(context, AppWidget.class);
        RemoteViews remoteViews = WidgetHelper.getInstance().generateRemoteViews(context);

        AppWidgetManager.getInstance(context).updateAppWidget(componentName, remoteViews);
    }
}

这是我启动闹钟的小部件的源代码:

public class AppWidget extends AppWidgetProvider {
    private AlarmManager alarmMgr;
    private PendingIntent alarmIntent;

static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
    RemoteViews remoteViews = WidgetHelper.getInstance().generateRemoteViews(context);
    appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    for (int appWidgetId : appWidgetIds) {
        updateAppWidget(context, appWidgetManager, appWidgetId);
    }
}

private void startWidgetAlarm(Context context){
    alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context, WidgetAlarmReceiver.class);
    intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
    alarmMgr.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis(), 60000, alarmIntent);
}

private void stopWidgetAlarm(Context context){
    alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context, WidgetAlarmReceiver.class);
    PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
    alarmMgr.cancel(sender);
}

@Override
public void onEnabled(Context context) {
    super.onEnabled(context);
    startWidgetAlarm(context);
}

@Override
public void onDisabled(Context context) {
    super.onDisabled(context);
    stopWidgetAlarm(context);
}
}

我的 list 的一部分:

<receiver android:name=".AppWidget">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>

    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/new_app_widget_info" />
</receiver>

<receiver android:name=".WidgetAlarmReceiver"  android:exported="false"/>

最佳答案

根据我的经验,最好使用一次性警报并在触发后重新注册它,因为对于重复警报,Android 可能会认为您在滥用 AlarmManager..所以这就是我正在使用的方法:

void registerOneTimeAlarm(PendingIntent alarmIntent, long delayMillis, boolean triggerNow) {
    int SDK_INT = Build.VERSION.SDK_INT;
    long timeInMillis = (System.currentTimeMillis() + (triggerNow ? 0 : delayMillis));

    if (SDK_INT < Build.VERSION_CODES.KITKAT) {
        alarmManager.set(AlarmManager.RTC_WAKEUP, timeInMillis, alarmIntent);
    } else if (Build.VERSION_CODES.KITKAT <= SDK_INT && SDK_INT < Build.VERSION_CODES.M) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, alarmIntent);
    } else if (SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, alarmIntent);
    }
}

也许它对你也有用。

关于android - 如何更新 OREO 中的 Widget(AlarmManager 在数小时/数天后停止),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49383379/

相关文章:

android - 操作栏出现空指针异常

Android:BatteryLevel 小部件未更新

android - 在 coordinatorLayout android 中的 navigationBar 下方设置布局

Qt 小部件与顶部的 QML 混合

python - 使用 .grid 将 tkinter 列表框的大小调整为最大项目的宽度

css - 我怎样才能让这个表单和按钮在响应式设计中正确调整大小?

android - 是否可以将网页或内容从 web 拉到 android 主屏幕上的小部件中?

java - 从小部件类连接到数据库

android - 通过蓝牙发送文件

android-layout - 由于某种奇怪的原因,按钮被转换到复选框?