Rafa
Rafa

Reputation: 3339

Java vs Kotlin generics

I have the following Java class I'm trying to convert to Kotlin that uses generics.

abstract class MvpViewHolder, M, V : View?>(itemView: View) : RecyclerView.ViewHolder(itemView) {

public abstract class MvpViewHolder<P extends BasePresenter> extends RecyclerView.ViewHolder {
    protected P presenter;

    public MvpViewHolder(View itemView) {
        super(itemView);
    }

    public void bindPresenter(P presenter) {
        this.presenter = presenter;
        presenter.bindView(this);
    }

    public void unbindPresenter() {
        presenter = null;
    }
}

Here is my Kotlin attempt

abstract class MvpViewHolder<P : BasePresenter>(itemView: View) : RecyclerView.ViewHolder(itemView) {

    protected var presenter: P? = null

    fun bindPresenter(presenter: P?): Unit {
        this.presenter = presenter
        presenter?.bindView(this)

    }

    fun unbindPresenter(): Unit {
        this.presenter = null
    }
}

I'm particularly running into a problem with the generics. It turns out that in Kotlin it's simply not enough to do MvpViewHolder<P : BasePresenter> as Kotlin requires that we pass in the 2 type arguments for BasePresenter (whose implementation I put below)

However, if I need to pass in the type arguments for BasePresenter then my method signature would then look like this

`abstract class MvpViewHolder<P : BasePresenter<*, *>>(itemView: View) : RecyclerView.ViewHolder(itemView) {`

This does not help me however, because in presenter.bindView(this) I get a type error of Required: Nothing, Found: MvpViewHolder

I could also get more specific and pass in MvpViewHolder<P: BasePresenter<M, V>, M, V> but then that would mean that wherever I call MvpViewHolder, I then also have to include 2 extra type parameters. Not only will that be tedious to deal with now having to maintain, but it just makes me sad.

How can I either get rid of the error when I use BasePresenter<,> or avoid having to pass in 3 type parameters into my MvpViewHolder class, just so I can define P as a BasePresenter

abstract class BasePresenter<M, V> {
    var model: M? = null

    var view: WeakReference<V>? = null

    fun setM(model: M?): Unit {
        this.model = model

        if (setupDone()) {
            updateView()
        }
    }

    fun bindView(view: V) {
        this.view = WeakReference(view)
    }

    fun unbindView() {
        this.view = null
    }

    abstract fun updateView()

    fun view(): V? {
        return if (view == null) null else view?.get()
    }

    fun setupDone(): Boolean {
        return view() != null && model != null
    }

}

Upvotes: 0

Views: 903

Answers (1)

Sangeet Suresh
Sangeet Suresh

Reputation: 2545

Change abstract class to the following code

 abstract class MvpViewHolder<P :BasePresenter<P,MvpViewHolder<P>>>(itemView: View) : RecyclerView.ViewHolder(itemView) {
        protected var presenter: P? = null
        fun bindPresenter(presenter: P) {
            this.presenter = presenter
            presenter.bindView(this)
        }

        fun unbindPresenter() {
            presenter = null
        }
    }

Upvotes: 1

Related Questions