Android - Kotlin - object must be declared abstrac

2020-03-19 03:13发布

问题:

I have set an ItemClickLister for my RecyclerView like this:

ItemClickSupport.addTo(recyclerView!!).setOnItemClickListener(
                    object : ItemClickSupport.OnItemClickListener {
                        override fun onItemClicked(recyclerView: RecyclerView?, position: Int, v: View?) {
                            val row = recyclerView!!.getChildAt(position)
                            val el = row.findViewById(R.id.active_expandablelayout) as ExpandableLayout

                            if (el.isExpanded) {
                                el.collapse()
                            } else {
                                el.expand()
                            }
                        }
                    }
            )

using the ItemClickSupport library which I translated into Kotlin.

I get an error on object (line 2) that says:

object must be declared abstract or implement abstract member.

I'm really new to Kotlin and I couldn't find any solution here on SO either.

Any help is greatly appreciated.

Edit:

Here is my ItemClickSupport.kt:

class ItemClickSupport private constructor(private val mRecyclerView: RecyclerView) {
    private var mOnItemClickListener: OnItemClickListener? = null
    private var mOnItemLongClickListener: OnItemLongClickListener? = null
    private val mOnClickListener = View.OnClickListener { v ->
        if (mOnItemClickListener != null) {
            val holder = mRecyclerView.getChildViewHolder(v)
            mOnItemClickListener!!.onItemClicked(mRecyclerView, holder.adapterPosition, v)
        }
    }
    private val mOnLongClickListener = View.OnLongClickListener { v ->
        if (mOnItemLongClickListener != null) {
            val holder = mRecyclerView.getChildViewHolder(v)
            return@OnLongClickListener mOnItemLongClickListener!!.onItemLongClicked(mRecyclerView, holder.adapterPosition, v)
        }
        false
    }
    private val mAttachListener = object : RecyclerView.OnChildAttachStateChangeListener {
        override fun onChildViewAttachedToWindow(view: View) {
            if (mOnItemClickListener != null) {
                view.setOnClickListener(mOnClickListener)
            }
            if (mOnItemLongClickListener != null) {
                view.setOnLongClickListener(mOnLongClickListener)
            }
        }

        override fun onChildViewDetachedFromWindow(view: View) {

        }
    }

    init {
        mRecyclerView.setTag(R.id.item_click_support, this)
        mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener)
    }

    fun setOnItemClickListener(listener: OnItemClickListener): ItemClickSupport {
        mOnItemClickListener = listener
        return this
    }

    fun setOnItemLongClickListener(listener: OnItemLongClickListener): ItemClickSupport {
        mOnItemLongClickListener = listener
        return this
    }

    private fun detach(view: RecyclerView) {
        view.removeOnChildAttachStateChangeListener(mAttachListener)
        view.setTag(R.id.item_click_support, null)
    }

    interface OnItemClickListener {

        fun onItemClicked(recyclerView: RecyclerView, position: Int, v: View)
    }

    interface OnItemLongClickListener {

        fun onItemLongClicked(recyclerView: RecyclerView, position: Int, v: View): Boolean
    }

    companion object {

        fun addTo(view: RecyclerView): ItemClickSupport {
            var support: ItemClickSupport? = view.getTag(R.id.item_click_support) as ItemClickSupport
            if (support == null) {
                support = ItemClickSupport(view)
            }
            return support
        }

        fun removeFrom(view: RecyclerView): ItemClickSupport {
            val support = view.getTag(R.id.item_click_support) as ItemClickSupport
            support?.detach(view)
            return support
        }
    }
}

This is a screenshot with the whole error and where it happens:

回答1:

Your interface and method signatures do not match. Your interface is declaring one function as:

fun onItemClicked(recyclerView: RecyclerView, position: Int, v: View)

And you override it as:

fun onItemClicked(recyclerView: RecyclerView?, position: Int, v: View?)

Those are not the same method signatures.

If this was a Java interface, you can override while changing nullability because it isn't clear what the nullability is (given no annotations in the Java code). But since you ported it to a Kotlin interface you must override using the same exact signature. You instead made both RecyclerView? and View? nullable which results in a mismatch to the original signature. Change your overridden function to be:

override fun onItemClicked(recyclerView: RecyclerView, position: Int, v: View)

Since this is a Kotin interface, you cannot use the SAM conversion to a Lambda so that is why the other answer previously provided does not work. If this was a Java interface, you could do that. You can track SAM conversions for Kotlin interfaces in KT-7770.

If you wanted this code to be more idiomatic Kotlin you would want function references or lambdas instead of interfaces, and you should just do that instead of relying on SAM conversion. You can read more about that in Higher-Order Functions and Lambdas. This is outside the scope of your question to go into more detail.



回答2:

Try with it:

ItemClickSupport.addTo(listView).setOnItemClickListener(object : ItemClickSupport.OnItemClickListener{
        override fun onItemClicked(recyclerView: RecyclerView, position: Int, v: View) {
            val row = recyclerView!!.getChildAt(position)
            val el = row.findViewById(R.id.active_expandablelayout) as ExpandableLayout

            if (el.isExpanded) {
                el.collapse()
            } else {
                el.expand()
            }
        }

    })