如何使用刷新按钮正确更新主屏幕小部件? (Android - 科特林)

How do I correctly update a home screen widget using a refresh button? (Android - Kotlin)

我创建了一个主屏幕小部件,它将显示比特币的当前价格,并带有一个刷新按钮,供用户手动获取价格数据。我将 Okhttp 用于 HTTP 请求,这部分工作正常。

但是,当将小部件添加到我的主屏幕时,它只响应按钮的某些次按下。我可以直观地看到按钮被按下,但没有任何反应。其他时候,它可以完美运行。我很好奇是什么导致了这种行为?

这是我的 AppWidgetProvider 的 onUpdate() 函数 class。

override fun onUpdate(
    context: Context,
    appWidgetManager: AppWidgetManager,
    appWidgetIds: IntArray
) {
    // There may be multiple widgets active, so update all of them
    for (appWidgetId in appWidgetIds) {
        
        val intent = Intent(context, PriceWidget::class.java)
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)

        val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
        val views = RemoteViews(context.packageName, R.layout.price_widget)

        views.setOnClickPendingIntent(R.id.refresh_button, pendingIntent)

        appWidgetManager.updateAppWidget(appWidgetId, views)
    }
}

按下按钮时,它会创建一个调用 AppWidgetProvider 函数 onReceive() 的 PendingIntent:

override fun onReceive(context: Context?, intent: Intent?) {
    super.onReceive(context, intent)
    println("Refresh button pressed!")

    if (intent!!.extras != null) {
        val appWidgetManager = AppWidgetManager.getInstance(context)
        val thisAppWidget = ComponentName(context!!.packageName, PriceWidget::class.java.name)
        val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
        for (appWidgetId in appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId)
        }
    }

这是我的 updateAppWidget 函数:

internal fun updateAppWidget(
    context: Context,
    appWidgetManager: AppWidgetManager,
    appWidgetId: Int
) {

    val views = RemoteViews(context.packageName, R.layout.price_widget)
    views.setTextViewText(R.id.appwidget_text, "Loading...")
    views.setTextViewText(R.id.price_change_widget, "24h: Loading...")
    appWidgetManager.updateAppWidget(appWidgetId, views)

    getWidgetData(views, appWidgetManager, appWidgetId)

}

最后,我的函数 getWidgetData 发出 HTTP GET 请求。根据响应,JSON 字符串使用 Gson 转换为 Data() 对象。此代码使用 RemoteView 更改文本并调用 appWidhetManager.updateAppWidget 函数。

// sets textView to current price
views.setTextViewText(R.id.appwidget_text, data.price())
views.setTextViewText(R.id.price_change_widget, data.change24h())

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

我关注了 Whosebug 的其他答案,none 似乎解决了这个问题。我注意到将两个小部件添加到主屏幕只能解决问题,直到删除其中一个小部件。

乐于接受所有建议 and/or 任何形式的帮助!如果我可以提供任何其他信息,请告诉我!

2021 年 10 月 27 日 -

我找到了一个可以用新信息刷新小部件的解决方案。

我从 AppWidgetProvider 的 onUpdate() 方法中删除了登录,所以现在它只有样板代码:

 override fun onUpdate(
    context: Context,
    appWidgetManager: AppWidgetManager,
    appWidgetIds: IntArray
) {
    // There may be multiple widgets active, so update all of them
    for (appWidgetId in appWidgetIds) {
        updateAppWidget(context, appWidgetManager, appWidgetId)
    }
}

现在,updateAppWidget() 方法具有所有逻辑。我创建了一个 RemoteView() 链接到主屏幕小部件的布局,使用 setTextViewText() 修改了小部件上的一些文本,然后调用 appWidgetManager.updateAppWidget(appWidgetId, views).

在同一个函数中,我通过创建一个 PendingIntent() 来继续逻辑,当按下刷新按钮时,我调用一个单独的函数来处理 HTTP GET 请求。

返回并处理数据后,我再次调用 appWidgetManager.updateAppWidget(appWidgetId, views)。由于这是从一个单独的函数发生的,因此我必须将 appWidgetManager 和 appWidgetId 作为变量传递。

我希望这可以帮助别人。按钮刷新现在基本上有 99% 的时间有效。它很少见,但我认为这与 Android 手机上的低功耗模式有关。这是我的 GitHub 的源代码:PriceWidget.kt