Kotlin adding a val field to subclass with multiple constructors

Viewed 531

I am creating a custom view in Android and I want to add a val field to the constructor, however View contains multiple constructors.

class CustomView : View {

    // I want a `val field: CustomField` in my constructor

    constructor(
        context: Context
    ) : super(context)

    constructor(
        context: Context,
        attrs: AttributeSet? = null
    ) : super(context, attrs)

    constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyle: Int = 0
    ) : super(context, attrs, defStyle)

    ...
}

Kotlin doesn't allow val fields in secondary constructors so I cannot do something like this:

class CustomView : View {

    constructor(
        val field: CustomField,
        context: Context
    ) : super(context)

    constructor(
        val field: CustomField,
        context: Context,
        attrs: AttributeSet? = null
    ) : super(context, attrs)

    constructor(
        val field: CustomField,
        context: Context,
        attrs: AttributeSet? = null,
        defStyle: Int = 0
    ) : super(context, attrs, defStyle)

    ...

How can I add a val field to the constructors but still extend the multiple constructors of the parent class?

  • I've tried adding the val to the secondary constructors, but Kotlin doesn't allow a val on a secondary constructor.
  • I've tried creating one primary constructor (the one I'm planning to explicitly use) and ignoring the others. Then Android Studio gives me a Lint warning that I'm missing constructors. (and I would like to know if there's a way to implement them all anyways)
  • I've tried adding the field I want as another parameter in the secondary constructor (not a val) and setting it in the secondary constructor body. This leads to the compiler complaining that the val is not initialized if I try to access in an init block and then the Linter still complains I am not implementing the super's constructors
class CustomView : View {

    val field: CustomField

    constructor(
        field: CustomField,
        context: Context
    ) : super(context) { this.field = field }

    ...
  • If the val I want is a primitive type I could pass it as part of the View's attribute set, however in this case it is not. Also I am hoping for a general Kotlin solution, if it exists.
1 Answers

You can do it in this way.

You will get error Property must be initialized or be abstract because field myCustomField must be initialized in every constructor of your class.

Also you cannot use keyword val in parameters

    class CustomView : View {

        val myCustomField : CustomField

        constructor(customField : CustomField, context: Context?) : super(context){
            this.myCustomField = customField
        }

        constructor(customField : CustomField ,context: Context?, attrs: AttributeSet?) : super(context, attrs){
            this.myCustomField = customField

        }
        constructor(customField : CustomField, context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
            context,
            attrs,
            defStyleAttr
        ){
            this.myCustomField = customField
        }

        constructor(
            customField : CustomField,
            context: Context?,
            attrs: AttributeSet?,
            defStyleAttr: Int,
            defStyleRes: Int
        ) : super(context, attrs, defStyleAttr, defStyleRes){
            this.myCustomField = customField
        }
    } 
Related