35

I am trying to make a interface Parcelable, as such I need a interface like this

interface AB : Parcelable {
    companion object {
        val CREATOR : Parcelable.Creator<AB>
    }
}

and my two classes A and B looking like

data class A (...): Parcelable{
    ...
    companion object {
        val CREATOR : Parcelable.Creator<AB> = object : Parcelable.Creator<AB> {
            override fun newArray(size: Int): Array<AB?> {
                return arrayOfNulls(size)
            }

            override fun createFromParcel(parcel: Parcel): AB {
                return A(parcel)
            }

        }
    }

I am struggling to implement such a interface in kotlin. It seems the interface class does not allow for the CREATOR

Perhaps I am taking the wrong approach,
I have a parcelable that contains a list of classes that are either A or B so I am doing

parcel.readTypedList(this.list, AB.CREATOR)

I require that the list be either A or B and that is why I am using an interface.

Anyone have any advice or a possible solution?

Brian
  • 14,610
  • 7
  • 35
  • 43
mickstar
  • 363
  • 1
  • 3
  • 5
  • If you are getting a specific compilation error, please post the error. – Doug Stevenson Feb 10 '16 at 23:40
  • Thank you everyone for your help, I dont think i described my problem well. Anyway I solved it by following this answer https://stackoverflow.com/questions/22576709/abstract-class-as-parcelable and rewriting the java to kotlin. Works well, only I am no longer using data classes. I tried ParcelPaper but it didn't work for me – mickstar Feb 11 '16 at 15:47

2 Answers2

56

In Kotlin, an interface can have a companion object but it is not part of the contract that must be implemented by classes that implement the interface. It is just an object associated to the interface that has one singleton instance. So it is a place you can store things, but doesn't mean anything to the implementation class.

You can however, have an interface that is implemented by a companion object of a class. Maybe you want something more like this:

interface Behavior {
   fun makeName(): String
}

data class MyData(val data: String) {
    companion object: Behavior {  // interface used here
        override fun makeName(): String = "Fred"
    }
}

Note that the data class does not implement the interface, but its companion object does.

A companion object on an interface would be useful for storing constants or helper functions related to the interface, such as:

interface Redirector {
    fun redirectView(newView: String, redirectCode: Int)

    companion object {
        val REDIRECT_WITH_FOCUS = 5
        val REDIRECT_SILENT = 1
    }
}

// which then can be accessed as:
val code = Redirector.REDIRECT_WITH_FOCUS
Jayson Minard
  • 84,842
  • 38
  • 184
  • 227
  • 6
    In the past, it was allowed to have generic constraints that said things like "any class that has a companion object implementing Xyz" and that vanished in early Kotlin, hopefully to resurface in the future as another type of generic constraint. Then you could generically talk about a class and its companion together. – Jayson Minard Feb 11 '16 at 13:37
  • I supposed this still is the state of things as of 4/13/17 in Kotlin? – Adam Hughes Apr 13 '17 at 21:14
  • @AdamHughes are you referring to generic constraints that include companion objects? If so, I don't think they have come back yet. – Jayson Minard Apr 16 '17 at 14:08
  • Jayson, I'm referring to specifically putting a companion object into an interface, as you've shown in your last code snippet of this answer. – Adam Hughes Apr 18 '17 at 15:58
10

By convention classes implementing the Parcelable interface must also have a non-null static field called CREATOR of a type that implements the Parcelable.Creator interface.

You need to annotate CREATOR property with @JvmField annotation to expose it as a public static field in containing data class.

Also you can take a look at https://github.com/grandstaish/paperparcel — an annotation processor that automatically generates type-safe Parcelable wrappers for Kotlin and Java.

Ilya
  • 21,871
  • 8
  • 73
  • 92
  • I don't think the first part of your answer helps. The second part is useful on its own. – Jayson Minard Feb 11 '16 at 16:17
  • @JaysonMinard In this situation it is required to satisfy Parcelable convention, I edited answer to explain why. – Ilya Feb 11 '16 at 16:44
  • great thanks, would it also need to be `JvmStatic`, or `JvmField` does that as well when in a companion object? – Jayson Minard Feb 11 '16 at 19:38
  • @JaysonMinard No, `JvmStatic` is for methods. This was recently sorted in docs: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods – Ilya Feb 17 '16 at 03:25
  • @JvmField does not work in the companion object of an interface so it seems. Any thoughts on why this is? – dumptruckman Jun 29 '17 at 20:13