简体   繁体   中英

Android updateAppWidget is called but not updating the widget or reaching RemoteViewsFactory?

My app widget (ListView showing game scores) works fine when created on the home screen, but when I call appWidgetManager.updateAppWidget(id, R.id.appwidget) inside the provider, there is no reaction from the widget or the log calls in the RemoteViewsFactory 's onCreate() or onDataSetChanged() methods. I know that the updateAppWidget gets called because I can see the log call right before it.

Why is the widget not updating?

My AppWidgetProvider:

class ScoresAppWidgetProvider : AppWidgetProvider() {

override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
        updateAllWidgets(appWidgetIds, context, appWidgetManager)
        super.onUpdate(context, appWidgetManager, appWidgetIds)
    }

private fun updateAllWidgets(appWidgetIds: IntArray, context: Context, appWidgetManager: AppWidgetManager) {
        appWidgetIds.forEach { appWidgetId ->
            updateWidget(appWidgetId, context, appWidgetManager, false)
        }

    }

override fun onReceive(context: Context, intent: Intent) {
        super.onReceive(context, intent)

        Log.i("TAG", "onReceive appWidgetId $appWidgetId") // This is logged and id is correct      
        if (intent.action.equals(ACTION_CLICK_REFRESH)) {
            appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.appwidget_list_view) // Works fine and updates the widget list
        } else if (intent.action.equals((ACTION_CLICK_SPOILERS_ON))) { // This is received
            updateWidget(appWidgetId, context, appWidgetManager, true)
        } else if (intent.action.equals((ACTION_CLICK_SPOILERS_OFF))) { // This is received
            updateWidget(appWidgetId, context, appWidgetManager, false)
        }
    }

private fun updateWidget(appWidgetId: Int, context: Context, appWidgetManager: AppWidgetManager, spoilers: Boolean) {
        
        val intent = Intent(context, AppWidgetService::class.java).apply {
            putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
            putExtra("testString", "Intent received")
            data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
        }

        // PendingIntent to refresh the appWidget contents
        val pendingRefreshClickIntent: PendingIntent = Intent(context, ScoresAppWidgetProvider::class.java).let {
            it.action = ScoresAppWidgetProvider.ACTION_CLICK_REFRESH
            it.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
            return@let PendingIntent.getBroadcast(context, appWidgetId, it, PendingIntent.FLAG_UPDATE_CURRENT)
        }

        // PendingIntent to toggle score spoilers
        val pendingSpoilersClickIntent: PendingIntent = Intent(context, ScoresAppWidgetProvider::class.java).let {
            it.action = if (spoilers) ScoresAppWidgetProvider.ACTION_CLICK_SPOILERS_ON else ScoresAppWidgetProvider.ACTION_CLICK_SPOILERS_ON
            it.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
            return@let PendingIntent.getBroadcast(context, appWidgetId, it, PendingIntent.FLAG_UPDATE_CURRENT)
        }

        // RemoteViews object for the app widget layout
        val remoteViews = RemoteViews(context.packageName, R.layout.appwidget).apply {
            if (spoilers) {
                setImageViewResource(R.id.btn_spoilers, R.drawable.avd_anim_turn_off_spoilers)
            } else {
                setImageViewResource(R.id.btn_spoilers, R.drawable.avd_anim_turn_on_spoilers)
            }
            
            setRemoteAdapter(R.id.appwidget_list_view, intent)
            setEmptyView(R.id.appwidget_list_view, R.id.empty_view)
            setOnClickPendingIntent(R.id.btn_refresh, pendingRefreshClickIntent)
            setOnClickPendingIntent(R.id.btn_spoilers, pendingSpoilersClickIntent)
        }

        Log.i(TAG, "updateWidget: Calling updateWidget!") // This is logged
        appWidgetManager.updateAppWidget(appWidgetId, remoteViews) // NO EFFECT FROM THIS CALL!!
    }

}

My RemoteViewsService and RemoteViewsFactory:

class AppWidgetService: RemoteViewsService() {
    override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
        return ListRemoteViewsFactory(this.applicationContext, intent)
    }
class ListRemoteViewsFactory(private val context: Context, val intent: Intent): RemoteViewsFactory {

...

        override fun onCreate() {
            Log.i(TAG, "onCreate: created!") // Logged when I add the widget first time, not logged when I call updateAppWidget() from AppWidgetProvider
            updateList()
        }

        override fun onDataSetChanged() {
            Log.i(TAG, "onDataSetChanged: changed!")
            updateList()
        }
...
    }
}

It seems the layout passed to the remoteViews is cached, and you have to use a different layout for it to work. I used two different layouts to update the widget based on a boolean, and it worked.

val remoteViews = if (spoilers) RemoteViews(context.packageName, R.layout.appwidget_spoilers) else RemoteViews(context.packageName, R.layout.appwidget_no_spoilers)

Layouts can be similar, but have to have some differences. In my case I used different drawables for an ImageView.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM