问题 Android小部件按钮停止工作


我有一个带有小部件的Android应用程序,它有按钮。 这段代码有效。

小部件上的按钮 停止工作 当事情发生时,例如改变手机的语言。我使用共享偏好,所以 如果用户重新安装应用程序(没有卸载),按钮再次工作 并且设置仍然是设置的。

  • 我注意到了我的意图 AppWidgetProvider class(此分析下的代码)未正确触发。
  • 我加了一个 Toast 消息给 Call1 从中实例化的类 AppWidgetProvider,但它不显示。
  • 我的 UpdateService.java 只是获取设置首选项和自定义窗口小部件的外观,所以我认为它可能与我的问题无关。
  • 我的 Main.java 文件只包含微调器并保存共享首选项,这意味着我在微调器中选择“计算机”,以便小部件上显示“计算机”文本。当我改变手机的语言时,它也不会消失,图像也不会消失。因此,我相信 UpdateService.java 一定没事

这是AppWidgetProvider类:

public class HelloWidget extends AppWidgetProvider {

    public static String ACTION_WIDGET_CONFIGURE = "ConfigureWidget";
    public static String ACTION_WIDGET_CONFIGURE2 = "ConfigureWidget";
    public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
    public static String ACTION_WIDGET_RECEIVER2 = "ActionReceiverWidget";
    private static final int REQUEST_CODE_FOUR = 40;
    private static final int REQUEST_CODE_FIVE = 50;
    private static final int REQUEST_CODE_SIX = 60;
    private static final int REQUEST_CODE_SEVEN = 70;
    private static final int REQUEST_CODE_EIGHT = 80;

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        context.startService(new Intent(context, UpdateService.class));
        //Intent widgetUpdateIntent = new Intent(context, UpdateService.class);
        //context.startService(widgetUpdateIntent );

         RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetmain2);

         //P1 starts Call1.class
         Intent configIntent4 = new Intent(context, Call1.class);
         configIntent4.setAction(ACTION_WIDGET_CONFIGURE);
         PendingIntent configPendingIntent4 = PendingIntent.getActivity(context, REQUEST_CODE_FOUR, configIntent4, 0);
         remoteViews.setOnClickPendingIntent(R.id.ImageView01, configPendingIntent4);

         //P2 starts Call2.class
         Intent configIntent5 = new Intent(context, Call2.class);
         configIntent5.setAction(ACTION_WIDGET_CONFIGURE);
         PendingIntent configPendingIntent5 = PendingIntent.getActivity(context, REQUEST_CODE_FIVE, configIntent5, 0);
         remoteViews.setOnClickPendingIntent(R.id.ImageView02, configPendingIntent5);

         //P3 starts Call3.class
         Intent configIntent6 = new Intent(context, Call3.class);
         configIntent6.setAction(ACTION_WIDGET_CONFIGURE);
         PendingIntent configPendingIntent6 = PendingIntent.getActivity(context, REQUEST_CODE_SIX, configIntent6, 0);
         remoteViews.setOnClickPendingIntent(R.id.ImageView03, configPendingIntent6);

         //P4 starts Call4.class
         Intent configIntent7 = new Intent(context, Call4.class);
         configIntent7.setAction(ACTION_WIDGET_CONFIGURE);
         PendingIntent configPendingIntent7 = PendingIntent.getActivity(context, REQUEST_CODE_SEVEN, configIntent7, 0);
         remoteViews.setOnClickPendingIntent(R.id.ImageView04, configPendingIntent7);

         //P5 starts Call5.class
         Intent configIntent8 = new Intent(context, Call5.class);
         configIntent8.setAction(ACTION_WIDGET_CONFIGURE);
         PendingIntent configPendingIntent8 = PendingIntent.getActivity(context, REQUEST_CODE_EIGHT, configIntent8, 0);
         remoteViews.setOnClickPendingIntent(R.id.ImageView05, configPendingIntent8);

         appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
   }

    @Override
    public void onReceive(Context context, Intent intent) {

        final String action = intent.getAction();
        if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) 
        {
            final int appWidgetId = intent.getExtras().getInt(
                    AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);
            if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) 
            {
                this.onDeleted(context, new int[] { appWidgetId });
            }
        } 
        else 
        {
            if (intent.getAction().equals(ACTION_WIDGET_RECEIVER)) 
            {
                String msg = "null";
                try {
                    msg = intent.getStringExtra("msg");
                    } catch (NullPointerException e) {
                    //Log.e("Error", "msg = null");
                    }
            }
            super.onReceive(context, intent);
            }
    }
}

我也有 EditPreferences.javaGlobalVars.java 和其他一些现在没有意义的课程。这些课程的名称不言而喻。

还有一件事。我也有 Widgetmain.java

  public class WidgetMain extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.widgetmain2);
    }
    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) 
    {
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetmain2);

          appWidgetManager.updateAppWidget(appWidgetId, remoteViews);

    }
}

编辑:这个怎么样: 

当我在同事的ZTE Blade上安装此应用程序时,窗口小部件上的文本视图未加载相应的文本,只是在strings.xml中确定了该文本。

当我重新安装应用程序(没有卸载)时,文本视图被加载,一切都很好。 这个问题不会出现在我的HTC Desire HD上。

textview在前面提到的UpdateService.java中加载(代码的一部分):

RemoteViews updateViews = new RemoteViews(this.getPackageName(), R.layout.main);
updateViews.setTextViewText(R.id.widget_textview, name);
ComponentName thisWidget = new ComponentName(this, HelloWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);

即使“name”是静态的(例如String name =“Something”),在第一次安装时仍未加载该textview。


2785
2017-07-13 20:09


起源

我在这个问题上开了一笔赏金,因为我几周没有取得任何进展。 - erdomester
你怎么不在你的更新功能中调用super.onUpdate()? - Delete
我称之为,我只是在某种程度上错过了代码。我尝试将它作为第一行以及onUpdate函数的最后一行:super.onUpdate(context,appWidgetManager,appWidgetIds); - erdomester
好的,对不起。我更仔细地阅读你的解决方案。我不明白的是你所谓的“更新服务”循环。你的服务究竟在做什么?看,我的小部件中不需要服务。我应该只设置一个计时器来定期检查小部件是否需要刷新? - KairisCharm


答案:


每当您通过“new RemoteViews”创建新实例时,尝试使用单击侦听器更新RemoteView。在某些情况下,可能会从XML中新加载RemoteView,因此需要重新分配点击侦听器。


5
2017-11-07 09:10



我发现每次更改窗口小部件时远程视图都需要传递挂起的意图。否则在更新时删除 - Konstantin Pribluda


我的UpdateService.java只是获取设置首选项并自定义窗口小部件的外观,所以我认为它可能与我的问题无关。

它可能是相关的,因为您可以使用它来“刷新”待处理的意图。我的appwidget中有类似的问题,在一些随机运行时间(小时)之后,图像按钮停止响应点击。

我找到了这个帖子: AppWidget按钮onClick停止工作

这句话:

每次使用后,待处理的意图都会被“烧毁”。你需要再次设置它。或者等待窗口小部件刷新,然后它也会发生,但这可能不是理想的方式。

鉴于小部件更新时间通常设置为许多小时或天(我的是86400000毫秒),以防止手机每隔这么多分钟停止暂停,您的小部件将不会经常在更新上运行。在更新服务中设置待处理的意图ALSO可能会阻止您描述的问题。每次更新服务运行时,都会重新创建待处理的意图。

我今天已经为我的appwidget添加了这个可能的修复程序,我必须等待,看看修复程序是否真的有效,但到目前为止还是那么好。

我在更新服务'循环中添加了以下代码,其中刷新了每个小部件:

for (int i=0; i<appWidgetIds.length; i++)
{
  appWidgetId=appWidgetIds[i];

  /* other stuff to do */

  RemoteViews views=new RemoteViews(context.getPackageName(), R.layout.example_appwidget);

  /* here you "refresh" the pending intent for the button */
  Intent clickintent=new Intent("net.example.appwidget.ACTION_WIDGET_CLICK");
  PendingIntent pendingIntentClick=PendingIntent.getBroadcast(context, 0, clickintent, 0);
  views.setOnClickPendingIntent(R.id.example_appwidget_button, pendingIntentClick);
  appWidgetManager.updateAppWidget(appWidgetId, views);

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

4
2017-10-18 22:46



经过一天的测试后,我可以验证我上面建议的修复确实有效。我不确定这是否应该被视为一种解决方法,因为我不知道问题是由错误还是“功能”引起的。 - aseq
我已经有了一个多月的上述解决方案,也适用于Android市场中的应用程序,这对我来说是一个令人满意的解决方案。 - aseq
请帮帮我!: stackoverflow.com/questions/29598491/... - Muhammad Ali


问题是您不能对窗口小部件进行部分更新,您必须设置所有窗口小部件功能,例如每次推送新的远程视图时的PendingIntent集。 (Partiall更新仅适用于API14及更高版本......)。

你的小部件丢失pendingIntents的原因是android系统保存了remoteView,并用它重建你的小部件,以防它重置小部件(memmory短缺,TaskManager / taskKiller正在使用等等),所以你必须在updateService中设置remoteView中窗口小部件的所有更新代码。否则,它只是不会再次设置pendingIntents。

所以只需将pendingIntents的代码设置添加到服务中,您的问题就会解决=]


1
2018-05-24 11:19





我认为PendingIntents可能需要传递一个标志,可能会尝试更改:

PendingIntent.getActivity(context, REQUEST_CODE, configIntent, 0);

至:

PendingIntent.getActivity(context, REQUEST_CODE, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);

来自PendingIntent 文件,我认为代码'0'未定义。在这种情况下,FLAG_UPDATE_CURRENT最有效,因为您可能希望每次单击按钮时更新Intent。


0
2017-08-09 23:16



这还没有解决问题...... - erdomester


鉴于您提供的所有信息,我会说更改首选项时未正确触发更新方法。

我希望经过这么多测试后,您已经验证了您的清单文件包含:

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

你确认了吗? onUpdate 曾经跑过吗?在我看来,如果在没有卸载的情况下重新安装应用程序可以解决您的问题,那可能是因为它强制进行更新调用。

仔细检查后,发现ScanPlayGames有一个点: 官方文档的例子 使用super.onUpdate()。请注意,它在方法的末尾使用它,但有几个 例子 在Internet状态下,您最好在方法开始时使用它。


0
2017-09-06 16:18



是的,清单中包含该行。 2.必须运行OnUpdate,因为图像视图在窗口小部件中有效。或者你的意思是什么? 3.我在代码中有super.onUpdate(),我从这里错过了它。 - erdomester
关于2.,我倾向于在这种情况下几乎每行记录消息,只是为了确定,并且如果可能的话也会进入代码。我推断其他东西可能会使图像有效。如果我是你,我还会记录。除此之外,我很茫然。希望你解决它! - Kheldar


我已经有很长一段时间了。我的小部件有按钮@(onUpdate)。该小部件具有更新服务。小部件上的按钮在发生某些事情时停止工作,例如:更改字体等。

当我重新安装应用程序时,该按钮再次起作用。最后,我意识到我从未在我的Service类中调用onUpdate。

从服务类调用onUpdate修复了问题。


0
2018-06-17 22:30