skip to Main Content

I had one learning project that require RecyclerView item to send his detailed data to another activity with getParcelableExtra, my problem is when I clicked the item, the data is null on detailsActivity then I check it with the log.d, and yes it’s null. any solution ;

here’s the code main activity

class MainMyRecyclerViewActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMyrecyclerviewMainBinding
    private lateinit var rvHeroes: RecyclerView
    private val list = ArrayList<Hero>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMyrecyclerviewMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        rvHeroes = binding.rvMymainRv
        rvHeroes.setHasFixedSize(true)
        list.addAll(listHeroes)
        showRecyclerList()
    }

    private fun showRecyclerList() {
        //on change orientation adapter behavior
        if (applicationContext.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            rvHeroes.layoutManager = GridLayoutManager(this, 2)
        } else {
            rvHeroes.layoutManager = LinearLayoutManager(this)
        }

        val listHeroAdapter = ListHeroAdapter(list)
        rvHeroes.adapter = listHeroAdapter

        listHeroAdapter.setOnItemClickCallBack(object : OnItemClickCallback {
            override fun onItemClicked(data: Hero) {
                showSelectedHero(data)
                sendIntent(data)
            }
        })
    }

    private fun sendIntent(dataHero: Hero) {
        val intent = Intent(this@MainMyRecyclerViewActivity, DetailsActivity::class.java)
        intent.putExtra("DATA", dataHero.photo)
        intent.putExtra("DATA", dataHero.name)
        intent.putExtra("DATA", dataHero.description)

        startActivity(intent)
    }

    private val listHeroes: ArrayList<Hero>
        get() {
            val dataName = resources.getStringArray(R.array.data_name)
            val description = resources.getStringArray(R.array.data_description)
            val dataPhoto = resources.obtainTypedArray(R.array.data_photo)
            val listHero = ArrayList<Hero>()
            for (i in dataName.indices) {
                val hero = Hero(dataName[i], description[i], dataPhoto.getResourceId(i, -1))
                listHero.add(hero)
            }
            return listHero
        }

    private fun showSelectedHero(hero: Hero) {
        Toast.makeText(this, "you selected ${hero.name}", Toast.LENGTH_SHORT).show()
    }
}

here’s the adapter

class ListHeroAdapter(private val listHero: ArrayList<Hero>) :
    RecyclerView.Adapter<ListViewHolder>() {

    private lateinit var onItemClickCallback: OnItemClickCallback

    fun setOnItemClickCallBack(onItemClickCallback: OnItemClickCallback) {
        this.onItemClickCallback = onItemClickCallback
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
        val view: View =
            LayoutInflater.from(parent.context).inflate(R.layout.item_myrecyclerview, parent, false)
        return ListViewHolder(view)
    }

    override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
        val (name, description, photo) = listHero[position]
        holder.imgPhoto.setImageResource(photo)
        holder.tvName.text = name
        holder.tvDescription.text = description
        holder.itemView.setOnClickListener {
            onItemClickCallback.onItemClicked(listHero[holder.adapterPosition])
        }
    }

    override fun getItemCount(): Int = listHero.size
}

this the target activity

class DetailsActivity : AppCompatActivity() {

    private lateinit var binding: ActivityDetailsBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityDetailsBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val data = intent.getParcelableExtra<Hero>("DATA")

        binding.tvDetailsNameHero.text = data?.name
        binding.tvDetailsDeskription.text = data?.description
        data?.photo?.let { binding.ivDetails.setImageResource(it) }

        Log.d("details data", data?.name.toString())

    }
}

here’s is data class I’ve using

@kotlinx.parcelize.Parcelize
data class Hero(
    var name: String,
    var description: String,
    var photo: Int
) : Parcelable

the interface

interface OnItemClickCallback {

    fun onItemClicked(data: Hero)
}

any suggestion will be good for me, thank you.

3

Answers


  1. The problem is here

    intent.putExtra("DATA", dataHero.photo)
    intent.putExtra("DATA", dataHero.name)
    intent.putExtra("DATA", dataHero.description)
    

    You are sending single item in your intent as a String with the same key name

    The first solution would be you need to send your class object
    And
    the second solution should send all extra parameters with different key names

    the First solution You need to pass your model class object in intent

    intent.putExtra("DATA",dataHero);
    

    instead of this

    private fun sendIntent(dataHero: Hero) {
            val intent = Intent(this@MainMyRecyclerViewActivity, DetailsActivity::class.java)
            intent.putExtra("DATA", dataHero.photo)
            intent.putExtra("DATA", dataHero.name)
            intent.putExtra("DATA", dataHero.description)
    
            startActivity(intent)
        }
    

    The Second solution send data like this with different key names

    intent.putExtra("PHOTO", dataHero.photo)
    intent.putExtra("NAME", dataHero.name)
    intent.putExtra("DESCRIPTION", dataHero.description)
    

    and receive data like this in your details activity

    val photo = intent.getStringExtra("PHOTO");
    val name = intent.getStringExtra("NAME");
    val description = intent.getStringExtra("DESCRIPTION");
    
    Login or Signup to reply.
  2. I think you’re problem is here.

    private fun sendIntent(dataHero: Hero) {
        val intent = Intent(this@MainMyRecyclerViewActivity, DetailsActivity::class.java)
        intent.putExtra("DATA", dataHero.photo)
        intent.putExtra("DATA", dataHero.name)
        intent.putExtra("DATA", dataHero.description)
    
        startActivity(intent)
    }
    

    What you’re doing here is putting the value of dataHero.photo into the Bundle with the key DATA. Then you’re overwriting that with dataHero.name, and then again with dataHero.description.

    You can see from the image below that there are a lot of overloaded methods that use the same name but assign a different type.

    enter image description here

    So you are able to assign almost any value to a particular key (DATA), and the reason the call to retrieve the Parcelable is null, is because the value of DATA in the end is not a Parcelable implementation. The last assignment was of type String, which does not implement the Parcelable interface.

    enter image description here

    As mentioned by @AskNilesh use
    intent.putExtra("DATA", dataHero) instead.

    Login or Signup to reply.
  3. Change sendIntent method to this:

    private fun sendIntent(dataHero: Hero) {
        val intent = Intent(this@MainMyRecyclerViewActivity, DetailsActivity::class.java)
        intent.putExtra("DATA", dataHero)
        startActivity(intent)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search