Виджет Android не реагирует на прикосновения

Я пытаюсь использовать очень простой код, чтобы запустить виджет Android, но безуспешно. Я огляделся повсюду и не нашел хорошего ответа.

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

Это мой AppWidgetProvider:

public class WordWidget extends AppWidgetProvider
{
    Integer touchCounter = 0;

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
        //This is run when a new widget is added or when the update period expires.
        Log.v("wotd",  "Updating " + appWidgetIds.length + " widgets");

        for(int x = 0; x < appWidgetIds.length; x++)
        {
            Integer thisWidgetId = appWidgetIds[x];

            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
            remoteViews.setTextViewText(R.id.mainText, touchCounter.toString());

            Intent widgetIntent = new Intent(context, WordWidget.class);
            widgetIntent.setAction("UPDATE_NUMBER");

            PendingIntent widgetPendingIntent = PendingIntent.getBroadcast(context, 0, widgetIntent, 0);

            remoteViews.setOnClickPendingIntent(R.id.widgetLinearLayout, widgetPendingIntent);
            appWidgetManager.updateAppWidget(thisWidgetId, remoteViews);
        }
    }

    @Override
    public void onReceive(Context context, Intent intent)
    {
        Log.v("wotd", "In onReceive with intent=" + intent.toString());
        if (intent.getAction().equals("UPDATE_NUMBER"))
        {
            Log.v("wotd", "In UPDATE_NUMBER");
            touchCounter++;
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
            remoteViews.setTextViewText(R.id.mainText, touchCounter.toString());
        } else
        {
            Log.v("wotd", "In ELSE... going on to super.onReceive()");
            super.onReceive(context, intent);
        }
    }
}

Это часть моего манифеста:

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >

    <receiver
        android:icon="@drawable/ic_launcher"
        android:name="com.example.mywidget.WordWidget"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            <action android:name="UPDATE_NUMBER" />
        </intent-filter>

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

</application>

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

Кроме того, если я сейчас добавлю другой виджет, оба будут отображать одинаковые значения и увеличиваться, даже если я просто коснусь одного из них. Есть ли способ для каждого виджета иметь свой собственный счетчик?

Спасибо!


person Sandy    schedule 13.05.2012    source источник


Ответы (1)


Собственно вы ответили на свой вопрос. Но давайте проясним некоторые вещи:

О. Виджеты приложений НЕ удаляются, пока они находятся на главном экране. Но они не принадлежат вам. Они выполняются в процессе работы домашнего приложения. Чтобы быть более конкретным, их представления работают в процессе домашнего приложения, поэтому вы видите свой виджет, но он не делает то, что вы ожидаете, и поэтому мы используем RemoteViews вместо Views для их обновления. .

B. AppWidgetProviders (в вашем случае класс WordWidget), с другой стороны, уничтожаются, как только завершается метод onReceive. Все переменные в них повторно инициализируются каждый раз, когда вызывается метод onReceive. Вот почему ваше число никогда не увеличивается. Целью AppWidgetProvider является обновление RemoteViews виджета и информирование вашего приложения о получении зарегистрированной широковещательной рассылки.

C. Метод onUpdate AppWidgetProvider предоставляет вам массив с идентификаторами виджетов, которые необходимо обновить. Это единственная кодовая точка, которую вы можете использовать для получения количества экземпляров вашего виджета и их идентификаторов. Из-за RemoteViews НЕТ способа получить какое-либо полезное значение из представлений вашего виджета (например, вы НЕ можете прочитать значение счетчика из TextView), поэтому вы должны использовать предоставленную информацию и ДЕЙСТВИТЕЛЬНО сохранять ваши значения счетчика для каждого идентификатора виджета. Когда вызывается следующий onUpdate, вы читаете значение из хранилища, увеличиваете его, обновляете виджет с новым значением, а затем сохраняете новое значение обратно.

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

Наконец, я заметил, что в вашем переопределении onReceive вы вызываете «super.onReceive», только если вы не получаете действие «UPDATE_NUMBER». Это НЕ является хорошей практикой, если нет ХОРОШЕЙ причины (это другая история) всегда вызывать super.onReceive в качестве первой или последней команды в вашем переопределении.

Надеюсь это поможет...

person ChD Computers    schedule 13.05.2012
comment
Потрясающе, большое спасибо! Я узнал больше из вашего ответа, чем часы чтения сообщений в блоге. В чем разница между вызовом super.onReceive() в качестве первой или последней команды метода onReceive()? У меня всегда был этот вопрос относительно супер. - person Sandy; 13.05.2012
comment
На самом деле это зависит от того, что вы делаете. Если вы хотите, например, выйти (вызвав return;) из метода где-то в середине, вам нужно сначала вызвать super (перед обратным вызовом), в противном случае вызовите его последним. Однако в Android есть и другие методы (если я хорошо помню, это Activity onDestroy), в которых сначала должен быть вызван super.onDestroy. В моих приложениях-виджетах я вызываю super.onReceive как последнюю команду... - person ChD Computers; 13.05.2012
comment
В onReceive() я изменил touchCounter, чтобы он равнялся случайному значению (например, так: touchCounter = new Random().nextInt(100);) и закомментировал, когда TextView изменяется в onUpdate(), но он по-прежнему не меняется Значение. Я пропустил что-нибудь еще? - person Sandy; 14.05.2012