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()? Так что для этого мне нужно было бы использовать какое-то постоянное хранилище?
Кроме того, если я добавлю другой виджет, оба будут показывать одинаковые значения и приращения, даже если я просто коснусь одного. Есть ли способ для каждого виджета иметь свой счетчик?
Спасибо!
2 ответа
На самом деле вы ответили на свой вопрос. Но давайте уточним некоторые вещи:
О. AppWidgets НЕ убиваются, пока они находятся на главном экране. Но они не принадлежат тебе. Они работают в процессе домашнего приложения. Чтобы быть более точным, их представления выполняются в процессе домашнего приложения, поэтому вы видите свой виджет, но он не выполняет то, что вы ожидаете, и поэтому мы используем RemoteViews вместо Views для их обновления.,
B. AppWidgetProviders (в вашем случае класс WordWidget), с другой стороны, уничтожаются, как только завершается метод onReceive. Все переменные в них переинициализируются каждый раз, когда вызывается метод onReceive. Вот почему ваш номер никогда не увеличивается. Назначение AppWidgetProvider - обновить RemoteViews виджета и сообщить вашему приложению, что зарегистрированный широковещательный сигнал поступил.
C. Метод onUpdate AppWidgetProvider предоставляет вам массив с идентификаторами виджетов, которые должны быть обновлены. Это единственная кодовая точка, которую вы можете использовать для получения количества экземпляров виджета и их идентификаторов. Из-за RemoteViews НЕТ способа получить какое-либо полезное значение из Views вашего виджета (например, вы НЕ можете прочитать значение счетчика из TextView), поэтому вы должны использовать предоставленную информацию и НЕ сохранять значения счетчика для каждого идентификатора виджета. Когда вызывается следующий onUpdate, вы читаете значение из хранилища, увеличиваете его, обновляете виджет новым значением и затем сохраняете новое значение обратно.
D. Если ваш виджет должен делать много вещей или медленных вещей (например, сети), когда пришло время обновлять себя, вы должны рассмотреть возможность использования службы для этого. Но в вашем случае (для увеличения числа) ваш подход вполне подходит, если вы сохраняете счетчики в постоянном хранилище или где-то еще.
Наконец, я заметил, что в своем переопределении onReceive вы вызываете super.onReceive, только если вы не получаете действие UPDATE_NUMBER. Это НЕ хорошая практика, если только для этого нет ХОРОШЕЙ причины (это другая история), всегда вызывайте super.onReceive в качестве первой или последней команды в вашем переопределении.
Надеюсь это поможет...
У меня была возможность создать AppWidget с вибрацией при касании. Вот мой работоспособный фрагмент (просто измените имя действия и идентификаторы представления):
class MyWidgetProvider : AppWidgetProvider() {
companion object {
const val TOUCH_ACTION = "com.tekelili.poe.TOUCH_ACTION"
const val EXTRA_ITEM = "com.tekelili.poe.t.EXTRA_ITEM"
}
override fun onUpdate(context: Context,appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
for (appWidgetId in appWidgetIds) {
updateMyAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == TOUCH_ACTION) {
val index: Int = intent.getIntExtra(EXTRA_ITEM, 0)
val myIntent = Intent(context, MockActivity::class.java)
.putExtra("INDEX", index.toString())
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
(context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator).vibrate(100)
context.startActivity(myIntent)
}
super.onReceive(context, intent)
}
internal fun updateMyAppWidget(context: Context, appWidgetManager: AppWidgetManager,appWidgetId: Int) {
val views = RemoteViews(context.packageName, R.layout.mock_layout_widget)
views.setOnClickPendingIntent(R.id.mock_textview,
getPendingIntent(context, appWidgetId, 123))
appWidgetManager.updateAppWidget(appWidgetId, views)
}
private fun getPendingIntent(context: Context, appWidgetId: Int, value: Int): PendingIntent {
val touchPendingIntent: PendingIntent = Intent(context, MyWidgetProvider::class.java).run {
action = TOUCH_ACTION
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
putExtra(EXTRA_ITEM, value)
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
PendingIntent.getBroadcast(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT)
}
return touchPendingIntent
}
}