J. Squillaro
J. Squillaro

Reputation: 175

Issue when implementing two AppWidgetProvider for two different Android Home Screen Widgets

My Objective:

Create two Android Home Screen widgets for an app of two different sizes (3x2 & 5x2) as discussed in this StackOverflow question: Multiple widget sizes. As mentioned, two classes that implement AppWidgetProvider() must be created that serve as the Kotlin business logic for each widget size. Each widget has its own layout XML and info XML.

The Implementation

EXAMPLEWidgetSmall.kt
package com.example.exampleapp

import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.widget.RemoteViews

/**
 * Implementation of App Widget functionality.
 */
class EXAMPLEWidgetSmall : AppWidgetProvider() {
    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)
        }
    }

    override fun onEnabled(context: Context) {
        // Enter relevant functionality for when the first widget is created
    }

    override fun onDisabled(context: Context) {
        // Enter relevant functionality for when the last widget is disabled
    }
}

internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
    val widgetText = context.getString(R.string.appwidget_text)
    // Construct the RemoteViews object
    val views = RemoteViews(context.packageName, R.layout.example_widget_small)
    views.setTextViewText(R.id.appwidget_text, widgetText)

    // Instruct the widget manager to update the widget
    appWidgetManager.updateAppWidget(appWidgetId, views)
}
EXAMPLEWidgetMedium.kt
package com.example.exampleapp

import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.widget.RemoteViews

/**
 * Implementation of App Widget functionality.
 */
class EXAMPLEWidgetMedium : AppWidgetProvider() {
    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)
        }
    }

    override fun onEnabled(context: Context) {
        // Enter relevant functionality for when the first widget is created
    }

    override fun onDisabled(context: Context) {
        // Enter relevant functionality for when the last widget is disabled
    }
}

internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
    val widgetText = context.getString(R.string.appwidget_text)
    // Construct the RemoteViews object
    val views = RemoteViews(context.packageName, R.layout.example_widget_medium)
    views.setTextViewText(R.id.appwidget_text, widgetText)

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

The Error

e: 
/Users/example/examplefolder/exampleapp/android/app/src/main/kotlin/com/example/exampleapp/EXAMPLEWidgetMedium.kt: (15, 13): Overload resolution ambiguity: 
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int): Unit defined in com.example.exampleapp in file EXAMPLEWidgetMedium.kt
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int): Unit defined in com.example.exampleapp in file EXAMPLEWidgetSmall.kt
e: /Users/example/examplefolder/exampleapp/android/app/src/main/kotlin/com/example/exampleapp/EXAMPLEWidgetMedium.kt: (28, 1): Conflicting overloads: internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int): Unit defined in com.example.exampleapp in file EXAMPLEWidgetMedium.kt, internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int): Unit defined in com.example.exampleapp in file EXAMPLEWidgetSmall.kt
e: /Users/example/examplefolder/exampleapp/android/app/src/main/kotlin/com/example/exampleapp/EXAMPLEWidgetSmall.kt: (15, 13): Overload resolution ambiguity: 
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int): Unit defined in com.example.exampleapp in file EXAMPLEWidgetMedium.kt
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int): Unit defined in com.example.exampleapp in file EXAMPLEWidgetSmall.kt
e: /Users/example/examplefolder/exampleapp/android/app/src/main/kotlin/com/example/exampleapp/EXAMPLEWidgetSmall.kt: (28, 1): Conflicting overloads: internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int): Unit defined in com.example.exampleapp in file EXAMPLEWidgetMedium.kt, internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int): Unit defined in com.example.exampleapp in file EXAMPLEWidgetSmall.kt

The Issue

The issue seems to revolve around internal fun updateAppWidget being used in both files causing an overload resolution ambiguity. If I try to change the name of this function, another error is thrown, as this deviates from the important function of the AppWidgetProvider() class. In this StackOverflow answer: How to add multiple widgets in the same app?, it is suggested that a "BaseWidget" class be created that implements AppWidgetProvider() and from which my two widget kt files would implement BaseWidget(). However I am unsure if this would solve the issue because I would still be trying to use the same internal function updateAppWidget(), nor how I would write this code (I am not familiar with Kotlin) because this var must vary in each file which defines each widget layout val views = RemoteViews(context.packageName, R.layout.example_widget_small). How can I fix this issue so that the app can compile with no errors and for these widgets can work so that I can continue with their layout? Thank you!

Upvotes: 2

Views: 612

Answers (1)

Zain
Zain

Reputation: 40830

I see both AppWidgetProviders are identical except for their layouts; so you would create an abstract parent class that has an abstract Int field for the layout int resource id that you must set in each widget sub-class with the corresponding layout resource.

And keep any shared code normally in the parent class. Now the RemoteViews can be implemented in the parent class with that Int field which has been set in the implemented child classes.

Here's the implementation of that:

Parent class:: make it abstract, add the abstract widgetLayout field; and keep the shared functionality

And for the error you face; you need to keep the internal fun updateAppWidget as a part of your parent class.

abstract class ParentWidgetProvider : AppWidgetProvider() {
    
    abstract var widgetLayout: Int // must be overiden by the child classes with the widget layout
    
    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)
        }
    }

    override fun onEnabled(context: Context) {
        // Enter relevant functionality for when the first widget is created
    }

    override fun onDisabled(context: Context) {
        // Enter relevant functionality for when the last widget is disabled
    }


    private fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
        val widgetText = context.getString(R.string.appwidget_text)
        // Construct the RemoteViews object
        val views = RemoteViews(context.packageName, widgetLayout) //
        views.setTextViewText(R.id.appwidget_text, widgetText)

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

And override the widgetLayout in the child classes:

Small widget

class EXAMPLEWidgetSmall : ParentWidgetProvider() {

    override var widgetLayout
        get() = R.layout.example_widget_small
        set(_) {R.layout.example_widget_small}

}

Medium widget (the same but with different layout file)

class EXAMPLEWidgetMedium : ParentWidgetProvider() {

    override var widgetLayout
        get() = R.layout.example_widget_medium
        set(_) {R.layout.example_widget_medium}

}

Upvotes: 3

Related Questions