Кнопки виджета Android перестают работать

У меня есть приложение Android с виджетами, у которого есть кнопки. Этот код работает.

Кнопки виджета перестают работать, когда что-то происходит, например, изменение языка телефона. Я использую общие настройки, поэтому, если пользователь переустанавливает приложение (без удаления), кнопки снова работают, а настройки остаются установленными.

  • Я заметил, что намерения в моем классе AppWidgetProvider (код под этим анализом) не запускаются надлежащим образом.
  • Я добавил сообщение Toast в класс Call1, созданный из AppWidgetProvider, но он не отображается.
  • My 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.java, GlobalVars.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.

Текстовые изображения - это загрузка в вышеупомянутом 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);

Даже если "имя" является статическим (например, String name= "Something" ), это текстовое представление по-прежнему не загружается при первой установке.

Ответ 1

Попробуйте обновить RemoteViews при прослушивании кликов всякий раз, когда вы создаете новый экземпляр с помощью "новых RemoteViews". Возможно, RemoteViews недавно загружены из XML в некоторых случаях, поэтому прослушиватели кликов должны быть переназначены.

Ответ 2

My UpdateService.java просто получает заданные настройки и настраивает внешний вид виджета, поэтому я не думаю, что это может быть связано с моей проблемой.

Возможно, это связано с тем, что вы можете использовать его для "обновления" ожидающего намерения. У меня есть аналогичная проблема в моем приложении, что кнопка изображения перестает отвечать на клики после некоторого случайного времени выполнения (часы).

Я нашел эту тему: Кнопка AppWidget onClick перестает работать

И эта цитата:

Ожидаемое намерение "сжигается" после каждого использования. Вам нужно снова установить его. Или подождите, пока виджет будет обновлен, тогда это тоже произойдет, но это, вероятно, не желаемый способ.

Учитывая, что время обновления виджета обычно устанавливается в течение многих часов или дней (мой 86400000 миллисекунд), чтобы предотвратить выключение телефона из-под паузы через каждые несколько минут, ваш виджет не будет часто запускаться onUpdate. Возможно, что установка ожидающего намерения ТАКЖЕ в службе обновления предотвратит описанную вами проблему. Каждый раз, когда служба обновления запускает ожидающее намерение, повторно создается.

Я сегодня добавил это возможное исправление в свой 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);
}

Ответ 3

Проблема заключается в том, что вы не можете выполнить частичное обновление для виджета, вы должны установить все функции виджетов, такие как набор PendingIntent, каждый раз, когда вы нажимаете новый remoteView. (Обновления Partiall доступны только для API14 и выше...).

Причина, по которой ваши виджеты теряют свои ожидающие действия, заключается в том, что система Android сохраняет файл дистанционного управления и перестраивает ваш виджет вместе с ним, если он сбрасывает виджет (нехватка memmory, TaskManager/taskKiller в использовании и т.д.), поэтому вы должны установить весь код обновления для виджета в remoteView в вашем updateService. В противном случае он просто не будет устанавливать ожидающие действия снова.

Итак, просто добавьте код, задающий параметры ожидания для службы, и ваша проблема будет решена. =]

Ответ 4

Я думаю, что PendingIntents может понадобиться флаг, переданный им, возможно, попробуйте изменить:

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

в

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

Из документа PendingIntent , я думаю, что код 0 равен undefined. В этом случае FLAG_UPDATE_CURRENT будет работать лучше всего, поскольку вы, вероятно, захотите обновить Intent каждый раз, когда нажимается кнопка.

Ответ 5

Учитывая всю предоставленную вами информацию, я бы сказал, что ваш метод обновления не срабатывает должным образом при изменении настроек.

Я ожидаю после стольких тестов, вы подтвердили, что ваш файл манифеста содержит:

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

Вы подтвердили, что onUpdate работает? Мне кажется, что если переустановка приложения без деинсталляции решает проблемы, возможно, это связано с тем, что он вызывает вызов обновления.

После тщательной проверки выясняется, что в ScanPlayGames есть точка: официальный пример документации использует super.onUpdate(). Обратите внимание, что он использует его в конце метода, но несколько примеров в Интернете, вам лучше использовать его в начале вашего метода,

Ответ 6

У меня была эта проблема в течение длительного времени. У моего виджета есть кнопка @(onUpdate). У виджета есть служба для обновлений. Кнопка на виджете перестает работать, когда что-то происходит, например: изменение шрифта и т.д.

Когда я переустанавливаю приложение, кнопка снова работает. Наконец, я понял, что я никогда не вызывал onUpdate в классе сервиса.

Вызов onUpdate из класса службы устранил проблему.

Ответ 7

Если у кого-то все еще есть эта проблема, попробуйте установить атрибут android: updatePeriodMillis в вашем AppWidgetProviderInfo; Операционная система может по разным причинам убить ожидающее намерение, и ваши кнопки могут перестать работать. Когда вы устанавливаете этот атрибут, вы сообщаете Android, когда он должен вызывать метод onUpdate в AppWidgetProvider, поэтому все ожидающие намерения будут воссозданы.