0

I have followed android developer documents to create the recycler view. But now I would like to make the item selectable.

Currently have created itemAdapter.kt

class ItemAdapter(
    private val context: Context,
    private val dataset: List<Mode>,
    private val itemClickListener: MainActivity
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder.

    class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView = view.findViewById(R.id.item_title)
    }

    /**
     * Create new views (invoked by the layout manager)
     */
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
        // create a new view
        val adapterLayout = LayoutInflater.from(parent.context)
            .inflate(R.layout.list_item, parent, false)

        return ItemViewHolder(adapterLayout)
    }

    /**
     * Replace the contents of a view (invoked by the layout manager)
     */
    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val item = dataset[position]
        holder.textView.text = context.resources.getString(item.stringResourceId)
        holder.itemView.setOnClickListener {
            itemClickListener.onItemClick(item) //here we are sending the mode object using interface
        }
    }

    /**
     * Return the size of your dataset (invoked by the layout manager)
     */
    override fun getItemCount() = dataset.size

    interface ItemClickListener {
        fun onItemClick(mode: Mode)
    }

}

Then there is data file called Modes.kt

class Modes {
    fun loadModes(): List<Mode> {
        return listOf(
            Mode(R.string.height),
            Mode(R.string.hleveldistance),
        )
    }
}

Then there is model file called Model.kt

data class Mode(val stringResourceId: Int)

How do I get the selected item for my function in the mainactivity.

class MainActivity : AppCompatActivity() {

    //private var etCommand: EditText? = null
    private var tvPalaute: TextView? = null
    private val modes = Modes().loadModes()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Initialize modes

 val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
        recyclerView.adapter = ItemAdapter(this, modes, this)
        // Use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        recyclerView.setHasFixedSize(true)

        //val etCommand: EditText = findViewById(R.id.et_command)
        val etSubmit: Button = findViewById(R.id.btn_submit)
        val etMeasure: Button = findViewById(R.id.btn_measure)

        tvPalaute = findViewById(R.id.tvPalaute)


        etSubmit.setOnClickListener {
                Toast.makeText(this, "Haetaan laite", Toast.LENGTH_SHORT).show()
                openActivityForResult()
        }

        etMeasure.setOnClickListener {
                Toast.makeText(this, "Aloitetaan mittaus", Toast.LENGTH_SHORT).show()
                openMeasureActivityForResult()
        }
    }

    fun onItemClick(mode: Mode) {
//openMeasureActivityForResult(mode) // update method to receive mode as an argument
        Log.d(mode.code, "mode code")
        Toast.makeText(this, "Mode is $mode", Toast.LENGTH_SHORT).show()
    }

    private fun openMeasureActivityForResult(mode: Mode) {
        val measureAction = "com.app.app.m"
        val intent = Intent()
        intent.action = measureAction
        //val selectedMode = mode?.Id
        //var mode = modes[selectedMode!!]
        intent.putExtra("Mode", mode?.code)
        Log.d(intent.toString(), "intent")
        intent.putExtra("AppName", "Example App")
        //if (!String.toString().isNullOrEmpty(Device))
        //{
          //  intent.putExtra("Device", Device);
        //}
        measureLauncher.launch(intent)
    }

This is my current state of the code. What should the openmeasureactivity function get as it parameter? And is the code looking allright since itemadapter is not in use now. And does the selected item look correct?

Jukka Koivu
  • 269
  • 4
  • 15

2 Answers2

0

I had the same problem, I made an interface for the on click, then in your fragment you override this fun with whatever you want to do.

// Here I add --> val itemClickListener: ItemClickListener
class MovieAdapter(
private val movies: List<Mode>, 
val itemClickListener: ItemClickListener) : RecyclerView.Adapter<MovieAdapter.ViewHolder>() {

    private lateinit var context: Context

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        private val binding = ItemMovieBinding.bind(itemView)

        fun bind(mode: Mode) {
            // Here we set the setOnClickListener
            itemView.setOnClickListener {itemClickListener.onClick(mode)}
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        context = parent.context
        // R.layout.item_mode --> change to yor layout
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_mode, parent, false)
        )
    }

    /**
     * Returns the size of the list
     */
    override fun getItemCount(): Int = movies.size

    /**
     * Called by RecyclerView to display the data at the specified position.
     */
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(movies[position])
    }
}
// The interface we can use in the fragment
interface ItemClickListener{
    fun onClick(mode: Mode)
}

then you can use the interface in your fragment:

override fun onClick(mode: Mode) {
   // here you can use the object
}
Stefan de Kraker
  • 333
  • 4
  • 14
0

You can user interface to pass objects to the activity.

Create an interface ItemClickListener with a method named onItemClick with a parameter of type, whatever you want to receive in your activity. For here use Mode

interface ItemClickListener {
    fun onItemClick(mode: Mode)
}

In your activity or fragment implement this interface, and override the onItemClick method to perform any operations on the selected Mode object.

class MainActivity : ItemClickListener {

    override fun onItemClick(mode: Mode) {
        openMeasureActivityForResult(mode) // update method to receive mode as an argument
    }

    private fun openMeasureActivityForResult(mode: Mode) { //use mode here
        val measureAction = "com.app.app.m"
        val intent = Intent()
        intent.action = measureAction
        //var mode = modes[SelectedMode] <-- here the selected value
        //intent.putExtra("Mode", mode.Code); <-- also here
        intent.putExtra("AppName", "Example App")
        //if (!String.toString().isNullOrEmpty(Device))
        //{
          //  intent.putExtra("Device", Device);
        //}
        measureLauncher.launch(intent)
    }
}

Change ItemAdapter to accept ItemClickListener in its constructor

class ItemAdapter(
    private val context: Context,
    private val dataset: List<Mode>,
    private val itemClickListener: ItemClickListener
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {


}

Inside onBindViewHolder() set a click listener to the holders itemView and pass mode object using the itemClickListener

override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val item = dataset[position]
        holder.textView.text = context.resources.getString(item.stringResourceId)
        holder.itemView.setOnClickListener {
            itemClickListener.onItemClick(item) //here we are sending the mode object using interface
        }
    }

In activity or fragment, when you create adapter just pass the instance of ItemClickListener's interface, we can pass it using this as we've already implemented it above.

val adapter = ItemAdapter(
    context,
    modeList,
    this 
)
Praveen
  • 3,186
  • 2
  • 8
  • 23
  • Hi, I tried this but not sure if I did it correctly. I updated my answer. It seems that itemAdapter is not used anywhere now. And openmeasure activity function wants some kind of parameter – Jukka Koivu May 09 '22 at 06:17
  • And I have button that starts that intent. – Jukka Koivu May 09 '22 at 06:28
  • Also it gives this when clicking item: ```js E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.app, PID: 31888 java.lang.ArrayIndexOutOfBoundsException: length=2; index=2131689515 at java.util.Arrays$ArrayList.get(Arrays.java:3766) at com.example.app.MainActivity.openMeasureActivityForResult(MainActivity.kt:71) at com.example.app.MainActivity.onItemClick(MainActivity.kt:62) at com.example.app.adapter.ItemAdapter.onBindViewHolder$lambda-0(ItemAdapter.kt:50) ``` – Jukka Koivu May 09 '22 at 12:17
  • `ArrayIndexOutOfBoundsException`, are you sure the index you are accessing is in the list? – Praveen May 09 '22 at 13:38
  • I got to show now the selected mode and id in the toast (updated my question), and i think it might be going also to the intent but I am getting resultcode 0 so im not sure if my mode.code is correct or incorrect when its returning the resultcode 0 and wont get any data out – Jukka Koivu May 10 '22 at 07:18
  • Seems that the selected value isn't going to the intent and results to the resultcode 0. ``` D/Bundle[{Mode=null, AppName=Example App, Device=1280}]: extras``` – Jukka Koivu May 10 '22 at 10:45
  • I got it working now. :) Just made global variable and then onClick function did this `selectedMode = mode.code` – Jukka Koivu May 12 '22 at 10:53