Martin
Martin

Reputation: 2914

How to update widget with data from Activity?

I want to update widget with data from my Activity every second. I have Item which has timers and its updating by onBind method sending payload to it. Every time it will update data and send new (Strings, Dates, Color resources) to payload, I want to update existing Widget with these data. I should update it every second as timer goes on. (payload is sent every second) Is this possible? Because I can add my data to extras and send Intent to AppWidgetProvider, but I don't know how to update views in Widget with new data sent into onReceive. Tried this code in onUpdate function. Which should be called every 1000ms which I set in xml for widget provider - android:updatePeriodMillis="1000". What is happening is Grey box on my homescreen with Problem loading widget text. No crashes or errors were present in logs.

RecyclerView item:

private fun updateWidgetTimer(text: String, color: Int){
        val int = Intent(a, WidgetProvider::class.java)
        int.apply {
            putExtra(WidgetProvider.REM_TIME, text)
            putExtra(WidgetProvider.REM_TIME_COLOR, color)
            action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
        }
    }

AppWidgetProvider:

   private var time: String = ""
   private var color: Int = R.color.colorGreen
   override fun onUpdate(
        context: Context?,
        appWidgetManager: AppWidgetManager?,
        appWidgetIds: IntArray?
    ) {
        val remoteViews = RemoteViews(context?.packageName, R.layout.widget_custom_layout)
        remoteViews.setTextViewText(R.id.timer, time)
        context?.let {
            remoteViews.setTextColor(R.id.timer, ContextCompat.getColor(context, color))
        }
    }

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

            val extras = intent?.extras

            extras?.let { 
                time = extras.getString(REM_TIME)?:""
                color = extras.getInt(REM_TIME_COLOR)
            }

        }

UPDATE: Payload is successfully send to onReceive, but as onUpdate is called, none of my widgets are updated with new data.

Example of my updated onUpdate function:

override fun onUpdate(
        context: Context?,
        appWidgetManager: AppWidgetManager?,
        appWidgetIds: IntArray?
    ) {

        context?.let {
            val currWidgetInstanceName = ComponentName(context, WidgetProvider::class.java)
            val widgetManager = AppWidgetManager.getInstance(context)

            val widgetIds = widgetManager.getAppWidgetIds(currWidgetInstanceName)

            widgetIds?.forEach {wId->
                val remoteViews = RemoteViews(context.packageName, R.layout.widget_layout)
                remoteViews.apply {
                    //set info title
                    setTextViewText(R.id.title, title)

                    //set subtitle
                    setTextViewText(R.id.subT, subt)

                    //set info
                    setTextViewText(R.id.info, info)

                    //set rem timer
                    setTextViewText(R.id.outTimer, remTime)
                    setTextColor(R.id.outTimer, ContextCompat.getColor(context, remTimeColor))
                }

                widgetManager?.updateAppWidget(currWidgetInstanceName, remoteViews)
            }

        }
    }

Upvotes: 1

Views: 2910

Answers (2)

Mariusz
Mariusz

Reputation: 1410

AppWidgetProvider.onUpdate is called by AppWidgetProvider.onReceive. Call super.onReceive(context, intent) at the end of onReceive method. Data will be updated before onUpdate will be called.

override fun onReceive(context: Context?, intent: Intent?) {
    val extras = intent?.extras

    extras?.let { 
        time = extras.getString(REM_TIME)?:""
        color = extras.getInt(REM_TIME_COLOR)
    }

    super.onReceive(context, intent)
}

Upvotes: 2

dustblue
dustblue

Reputation: 551

From https://developer.android.com/reference/android/appwidget/AppWidgetProviderInfo

Note: Updates requested with updatePeriodMillis will not be delivered more than once every 30 minutes.

If you want frequent updates, you should use

AlarmManager

Use a service and update the widget, example:

Intent intent = new Intent(context, WidgetUpdateService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pending);
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME,
    SystemClock.elapsedRealtime(), 1000, pendingIntent);

Upvotes: 1

Related Questions