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.
CodePudding user response:
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");
CodePudding user response:
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.
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.
As mentioned by @AskNilesh use
intent.putExtra("DATA", dataHero)
instead.
CodePudding user response:
Change sendIntent method to this:
private fun sendIntent(dataHero: Hero) {
val intent = Intent(this@MainMyRecyclerViewActivity, DetailsActivity::class.java)
intent.putExtra("DATA", dataHero)
startActivity(intent)
}