6

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:

screenshot

Daniele
  • 4,163
  • 7
  • 44
  • 95
  • 1
    You are leaving out information: 1) the interface definition for OnItemClickedListener, share it so we are not guessing, it should be in the question. 2) You are leaving out the full error message, what member name is it complaining about isn't implemented (just in case you did something in that interface we cannot see). 3) if you use the lambda version as suggested in one of the answers below it is telling you what is going on but without the original interface we cannot tell you how to interpret that. – Jayson Minard May 25 '17 at 22:08
  • @JaysonMinard please take a look at the updated question – Daniele May 26 '17 at 06:04
  • thanks, now we have the information needed to answer the question. The Java version of that implementation would be different than the same thing written in Kotlin due to Kotlin being more specific about talking to Kotlin code, and a little looser when talking to Java code. – Jayson Minard May 26 '17 at 13:33

2 Answers2

9

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.

Jayson Minard
  • 84,842
  • 38
  • 184
  • 227
  • Great answer this fixed my problem. Thanks also for the advices on kotlin, I'm trying to learn because it's really fast and convenient to use. – Daniele May 26 '17 at 19:45
-1

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()
            }
        }

    })
Master Disaster
  • 729
  • 4
  • 21
  • I did, doing like this I get a type mismatch expected ItemClickSupport.OnItemClickListener, found (???, ???, ???) -> Unit. If I explicit the type of the parameters I get (RecyclerView, Int, View) -> Unit, but the error is still there obviously – Daniele May 25 '17 at 20:42
  • Are you sure that you use properly `import`? – Master Disaster May 25 '17 at 20:43
  • I imported the ItemClickSupport class – Daniele May 25 '17 at 20:45
  • Are you using the ItemClickSupport Library? Have you translated it in Kotlin using Android Studio built in command? – Daniele May 25 '17 at 20:48
  • I copied you code to my project and it works fine. Check imports, clean, build – Master Disaster May 25 '17 at 20:55
  • It doesn't, there's still some problem there. Please have a look at the updated question – Daniele May 26 '17 at 06:05
  • This answer cannot work because his interface is written in Kotlin which does not support automatic SAM conversion to a lambda. If he had left the original code in Java, this would work. But this answer is invalid now that we see he wrote it in Kotlin. – Jayson Minard May 26 '17 at 13:32
  • @Jayson Minard, you are not correct. I have `ItemClickSupport` in java written and my code which is using this ItemClickSupport is in Kotlin. – Master Disaster May 26 '17 at 16:06
  • @MasterDisaster the question being asked is using a Kotlin port of ItemClickSupport, and your answer is using a Java version of ItemClickSupport, so your answer will not work for the question being asked. "using the ItemClickSupport library which I translated into Kotlin" he says, and now includes the actual Kotlin code. So your answer does not reflect the reality of the question. – Jayson Minard May 26 '17 at 16:15
  • Ok, check my edited answer. I copied ItemClickSupport.kt to my project and it still works for me. – Master Disaster May 26 '17 at 16:28