Kotlin -How to call finish() in a RecyclerViewAdapter using Binding (not context)

94 Views Asked by At

I need to finish() the Activity that the RecyclerView is in when an item/row is tapped.

I looked this up but most of the answers referred to the old way of doing things when using context and (context as MyActivity).finish(). How can I do the same thing using binding

class MyAdapter(var users: List<User>): RecyclerView.Adapter<MyAdapter.UserViewHolder>() {

    inner class UserViewHolder(private val binding: UserRowBinding): RecyclerView.ViewHolder(binding.root) {

        init {
            binding.root.setOnClickListener {

                val intent = Intent(binding.root.context, NextActivity::class.java)
                binding.root.context.startActivity(intent)

                // call finish() here
            }
        }
    }
}

class MyActivity: App: AppCompatActivity() {

    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...

        val adapter = MyAdapter(some_array_Of_users)
        binding.recyclerView.adapter = adapter
    }
}
2

There are 2 best solutions below

3
Christian Miranda On BEST ANSWER

You can also create a listener function on the activity itself.

In Adapter, you can add a variable for your listener. (or you can just add this as parameter of Adapter)

val listener: (()->Unit)? = null

In ViewHolder, add listener as your parameter and invoke it in setOnClickListener, it should look like this:

  inner class UserViewHolder(private val binding: UserRowBinding, private val listener: (()->Unit)? = null): RecyclerView.ViewHolder(binding.root) {

    init {
        binding.root.setOnClickListener {
            listener?.invoke()
        }
    }
}

In your Activity, you can just set the variable listener value. In that case, you can set the 'finish()' that you are looking for. Something look like this,

class MyActivity: App: AppCompatActivity() {

lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // ...

    val adapter = MyAdapter(some_array_Of_users)
    adapter.listener = { moveToOtherActivity() }
    this.adapter = adapter
}

  private fun moveToOtherActivity() {
      val intent = Intent(this@MainActivity, NextActivity::class.java)
      startActivity(intent)
      finish()
    }
}

or just add a parameter in your adapter,

class MyAdapter(var users: List<User>, val listener: (()->Unit?=null): RecyclerView.Adapter<MyAdapter.UserViewHolder>()

And in Activity,

 val adapter = MyAdapter(some_array_Of_users, {moveToOtherActivity()})

I hope this helps.

0
Mikhail Guliaev On

finish() is the method of the Activity class. So your task can be rephrased as

How I can get the reference on the Activity from my Adapter?

So you have at least 2 options:

  1. Use your itemView to get the Context:

    (itemView.context as Activity).finish()
    
  2. Get the Context from binding:

    (binding.root.context as Activity).finish()
    

Small advice:

Also you can consider to delegate click handling to the caller side and pass it to the adapter. It may be more correct in terms of architecture. And there will not be a problem to find the reference to your Activity. Something like this:

class MyAdapter(var users: List<User>, private val onClick: OnClickListener): RecyclerView.Adapter<MyAdapter.UserViewHolder>() {

    inner class UserViewHolder(private val binding: UserRowBinding): RecyclerView.ViewHolder(binding.root) {

        init {
            binding.root.setOnClickListener {
                onClick()
            }
        }
    }
}

class MyActivity: App: AppCompatActivity() {

    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...

        val adapter = MyAdapter(some_array_Of_users) {                     
            val intent = Intent(binding.root.context, NextActivity::class.java)
            startActivity(intent)
            [email protected]()
        }
        binding.recyclerView.adapter = adapter
    }
}