当前位置: 首页 > 知识库问答 >
问题:

Android AppWidget有时不更新

仲璞瑜
2023-03-14
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="250dp" android:minHeight="110dp" android:updatePeriodMillis="0"
    android:initialLayout="@layout/app_widget"
    android:widgetCategory="home_screen|keyguard"
    android:initialKeyguardLayout="@layout/app_widget"
    android:previewImage="@drawable/preview_image" />

以下是我的AppWidgetProvider类的相关部分:

public class MyAppWidget extends AppWidgetProvider {

    private static PendingIntent service1 = null, service2 = null, update_service = null;

    public static void nullifyService( String service_name ) {
        if ( service_name.equals( "service1" ) ) {
            service1 = null;
        } else {
            service2 = null;
        }
    }

    public static void updateMyWidget(final Context context, AppWidgetManager appWidgetManager, int appWidgetId) {

        /* ... code to update my widget ... */
        /* ... this code is tested and I know it works ... */

        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

        // set alarms if necessary for the beginning and end of the next void
        if ( null ==  update_service || ( null == service1 && null == service2 ) ) {

            final AlarmManager m = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

            // set alarms for the beginning and end of the upcoming/current event window
            if ( null == service1 && null == service1 ) {
                final Calendar s1_c = Calendar.getInstance(), // service1 alarm time
                               s2_c = Calendar.getInstance(); // service2 alarm time
                final Intent   s1_i = new Intent(context,MyService.class).putExtra( "serviceName", "service1" ),
                               s2_i = new Intent(context,MyService.class).putExtra( "serviceName", "service2" );
                final long s1_millis, s2_millis;

                // get the current VOC info
                if ( db == null ) db = new MyDataBase(context);
                alarm_info = db.getCurrentAlarms();

                // alarm times for service1 and service2 are UNIX timestamps
                // pulled from a sqlite database (tested and working fine)
                s1_c.setTime(new Date(alarm_info.getLong(4) * 1000 ));
                s2_c.setTime(new Date(alarm_info.getLong(1) * 1000 ));

                // if it is still before the next service1 alarm time
                // set an alarm for the exact time
                if ( s1_c.getTimeInMillis() > Calendar.getInstance().getTimeInMillis() ) {
                    s1_c.set(Calendar.MILLISECOND, 0);
                    s1_c.set(Calendar.SECOND, 0);
                    service1 = PendingIntent.getService(context, 0, s1_i, PendingIntent.FLAG_ONE_SHOT );
                    s1_millis = SystemClock.elapsedRealtime() + s1_c.getTime().getTime() - System.currentTimeMillis();
                    m.setExact(AlarmManager.ELAPSED_REALTIME, s1_millis, service1);
                }

                // set the alarm for the service2 alarm time
                s2_c.set(Calendar.MILLISECOND, 0);
                s2_c.set(Calendar.SECOND, 0);
                service2  = PendingIntent.getService(context, 1, s2_i, PendingIntent.FLAG_ONE_SHOT );
                s2_millis = SystemClock.elapsedRealtime() + s2_c.getTime().getTime() - System.currentTimeMillis();
                m.setExact(AlarmManager.ELAPSED_REALTIME, s2_millis, service2);
            }

            // set the widget to update every 15 minutes regardless
            if ( null == update_service ) {
                final Intent up_i = new Intent(context,MyService.class).putExtra( "serviceName", "update" );
                update_service = PendingIntent.getService(context, 2, up_i, PendingIntent.FLAG_CANCEL_CURRENT);
                m.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), 15 * 60 * 1000, update_service);
            }
        }

        // There may be multiple widgets active, so update all of them
        for( int appWidgetId : appWidgetIds) {
            updateMyWidget(context, appWidgetManager, appWidgetId);
        }
    }

    @Override
    public void onDisabled(Context context) {
        // Enter relevant functionality for when the last widget is disabled
        final AlarmManager m = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        m.cancel(service1);
        m.cancel(service2);
        m.cancel(update_service);
    }
}

下面是我的service类的相关部分:

public class MyService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){

        // update all of the widgets
        ComponentName cn = new ComponentName(this, MyAppWidget.class);
        AppWidgetManager m = AppWidgetManager.getInstance(this);
        for ( int awid : m.getAppWidgetIds(cn) ) {
            MyAppWidget.updateMyWidget(this,m,awid);
        }
        String service_name = intent.getStringExtra( "serviceName" );
        if ( "service1" == service_name || "service2" == service_name ) {
            MyAppWidget.nullifyService(service_name);
        }
        return START_NOT_STICKY;
    }
}
  1. update_service工作良好,每15分钟更新一次小部件
  2. 正在设置Service1Service2的警报。
ELAPSED #0: Alarm{41a9e1b8 type 3 com.mycompany.myappwidget}
    type=3 whenElapsed=231265839 when=+11m52s295ms window=-1 repeatInterval=900000 count=0
    operation=PendingIntent{41dbf158: PendingIntentRecord{41cf7920 com.mycompany.myappwidget startService}}
ELAPSED #4: Alarm{433d1560 type 3 com.mycompany.myappwidget}
    type=3 whenElapsed=90066209 when=+4h34m36s121ms window=0 repeatInterval=0 count=0
    operation=PendingIntent{41f0ec28: PendingIntentRecord{41f1e690 com.mycompany.myappwidget startService}}
com.mycompany.myappwidget +1s857ms running, 0 wakeups:
    +1s817ms 0 wakes 83 alarms: cmp={com.mycompany.myappwidget/com.mycompany.myappwidget.d}
    +40ms 0 wakes 1 alarms: cmp={com.mycompany.myappwidget/com.mycompany.myappwidget.c}

我做错了吗?平均而言,更新似乎只需要大约200ms,因此也许我应该使用PendingIntent.getBroadcast()并调用Android.AppWidget.Action.AppWidget_Update而不是创建服务来处理更新。这快把我逼疯了,所以任何可能给我指明正确方向的暗示或线索都将不胜感激。

@karakuri的回答教会了我如何区分pendingintent对象,以避免它们在设置警报时相互覆盖。下面是我修复此代码的方法:

  1. 我将putExtra()调用更改为setAction()并将操作设置为预定义常量之一,例如intent.action_main,这在语义上似乎与服务正在执行的操作类似
  2. 我从类级作用域中删除了所有服务,因为事实证明没有必要在调用onupdate()
  3. 之间保留它们
  4. 我删除了onupdate()
  5. 中的所有条件逻辑
  6. 我返回到使用内置的android更新机制,即将app_widget_info.xml中的android:updatePeriodMillis更改为1800000(30分钟),并摆脱了用setrepeating()
  7. 设置的重复警报ID
  8. 我发现我的警报的边界条件有一个问题,它阻止了UI在我认为应该更新的时候进行更新--但是,如果我没有开始使用setAction()
  9. 的话,我是不会发现这个问题的

非常感谢!!!

共有1个答案

宗波涛
2023-03-14

这里是我的建议,希望这里的某个地方能解决你的问题。

>

  • 不要使用==来比较服务中(或任何地方)的字符串。将.equals()与命名常量一起使用。

    您的pendingintent只有附加项不同。当您将相同的intent赋予pendingintent时,它只保留其中一个。为了比较intent,不考虑附加项(请参阅pendingintent的文档)。我不使用附加项,而是给每个intent一个不同的操作,并在您的服务中使用intent.getAction()

  •  类似资料:
    • 我现在迷路了。

    • 问题内容: 我有一个ng-repeat,它在更改正在使用的数组中的数据时不会更新。我已经研究了一段时间,但似乎没有任何效果。最初,当页面加载时,ng- repeat显示数据集的第一页,在获取新数据(下一页)并使用该数据设置该数组时,ng- repeat不会注意到更改,并且永远不会填充更新的数组。如果有人可以在正确的方向上指导我,将不胜感激。 }]); 问题答案: 尝试将tbody包装在div中,但

    • UserViewModel: 用户存储库:

    • 基本上,这个程序是一个9x9矩阵,其中每个单元格都需要用某些数字更新。我有一个矩阵表。将其初始化为0。程序正在工作,但在一切完成后仅更新一个表。(找到解决方案)。 由于数据在幕后更改,表单元格不会更新。整个表在程序执行结束时更新。但我想在给每个单元格赋值时看到每个数字实时变化。非常感谢任何代码帮助。 我也在没有容器的情况下尝试了这个。但这也没有更新表。我做的研究告诉我,setImite(true)

    • 问题内容: 我在mysql表中具有属性为“ ON UPDATE CURRENT_TIMESTAMP”的时间戳。有没有办法在特殊情况下手动禁用更新时间戳?(例如:更新条目以修改博客文章,但不重新添加日期) 问题答案: 有没有办法在特殊情况下手动禁用更新时间戳?(例如:更新条目以修改博客文章,但不重新添加日期) 听起来您需要配置默认约束,以便仅在插入时填充列: 将其更改为仅这意味着任何修订都不会触发时

    • 问题内容: 我创建了以下示例,以便您可以确切了解正在发生的事情:http : //jsfiddle.net/8t2Ln/101/ 如果我使用ng-options,也会发生同样的事情。我这样做有不同的原因,但由于简化了示例,所以省略了这一部分。 如您所见,默认情况下它具有两个选项。我将在选择旁边显示ng- model的选择值,以便您可以看到它的含义。当您在顶部添加第三个选项时,它会将值设置为该新选项