Issue
I am very beginner to Android Kotlin, I am developing a practice app which requires a selected data from recycler view to be in an arraylist. Selection works fine until I change my spinner value and items get reloaded, once items get reloaded it take two clicks to deselect but is still not removed from the selected data arrayList. (whenever spinner value is changed, data is loaded from API). I know this code is messy and has a lot of unnecessary stuff, if someone could help me with how to clean the code and solve the issue, will be very glad.
class RecyclerViewAdapter(val dataList:ArrayList<ModelClass>):RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>(){
object ob {
val dataSelected= ArrayList<ModelClass>()
}
private var _binding: ItemViewBinding? = null
private val binding get() = _binding!!
private lateinit var nListener : onItemClickListener
interface onItemClickListener{
fun onItemClick(position: Int)
}
fun setOnItemClickListener(listener:onItemClickListener){
nListener=listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewAdapter.ViewHolder {
val v=LayoutInflater.from(parent.context).inflate(R.layout.item_view,parent,false)
_binding= ItemViewBinding.bind(v)
return ViewHolder(binding.root)
}
fun bindItems(data:ModelClass){
binding.itemQuant.text=data.item_quant
binding.itemName.text=data.item_name
binding.mfgName.text=data.mfg
binding.quantity.text=data.item_stock.toString()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.restore()
bindItems(dataList[position])
holder.select()
}
@SuppressLint("ResourceAsColor")
inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
fun restore(){
for (i in 0 until ob.dataSelected.size){
for (j in 0 until dataList.size){
if (ob.dataSelected[i].sku_code==(dataList[j]).sku_code) {
if(adapterPosition == j){
itemView.isSelected = true
itemView.setBackgroundColor(R.color.black)
println("****")
}
}
}
}
}
fun select(){
itemView.setOnClickListener {
val position: Int = adapterPosition
if (ob.dataSelected.contains(dataList[position]) ){
itemView.setBackgroundResource(0)
itemView.isSelected = false
ob.dataSelected.remove(dataList[position])
for (i in 0 until ob.dataSelected.size){
println(ob.dataSelected[i].sku_code)
}
}
else {
itemView.isSelected = true
itemView.setBackgroundColor(R.color.black)
ob.dataSelected.add((dataList.get(position)))
for (i in 0 until ob.dataSelected.size){
println(ob.dataSelected[i].sku_code)
}
}
}
}
}
override fun getItemCount(): Int {
return dataList.size
}
override fun getItemId(position: Int): Long = position.toLong()
} . . . . . . edit:
class RecyclerViewAdapter(val dataList:ArrayList,val onItemClicked: (Int) -> Unit):RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>(){
object ob { val dataSelected= ArrayList()
}
private var checkedPosition = -1
fun setData(listModel: List<ModelClass>) {
dataList.clear()
dataList.addAll(listModel)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemViewBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return ViewHolder(binding, parent.context)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(dataList[position])
}
override fun getItemCount() = dataList.size
inner class ViewHolder(
val binding: ItemViewBinding,
val context: Context
): RecyclerView.ViewHolder(binding.root) {
@SuppressLint("ResourceAsColor", "ResourceType")
fun bindItems(data: ModelClass) = with(binding) {
/*
* Map Your data Here
* example: tvTitle.text = model.title
* */
binding.itemQuant.text=data.item_quant
binding.itemName.text=data.item_name
binding.mfgName.text=data.mfg
binding.quantity.text=data.item_stock.toString()
when (checkedPosition) {
-1 -> {
itemView.setBackgroundResource(0)
}
else -> when (checkedPosition) {
adapterPosition -> {
itemView.setBackgroundColor(R.color.black)
}
else -> {
itemView.setBackgroundResource(0)
}
}
}
root.setOnClickListener {
itemView.setBackgroundResource(R.color.black)
if (checkedPosition != adapterPosition) {
notifyItemChanged(checkedPosition)
checkedPosition = adapterPosition
}
// Handle the clicked item
if (ob.dataSelected.contains(dataList[adapterPosition])){
ob.dataSelected.remove(dataList[adapterPosition])
itemView.isSelected=false
for (i in ob.dataSelected){
println(i.sku_code)
}
itemView.setBackgroundColor(R.color.black)
}
else {
ob.dataSelected.add(dataList[adapterPosition])
itemView.isSelected=true
for (i in ob.dataSelected){
println(i.sku_code)
}
itemView.setBackgroundResource(0)
}
onItemClicked.invoke(adapterPosition)
}
}
}
}
Solution
here try this one, i tried refactoring your code
class RecyclerViewAdapter(
val onItemClicked: (Int) -> Unit
) : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() {
private val data = ArrayList<ModelClass>()
private var checkedPosition = -1 // -1: No Item Selected, 0: First Item Selected
fun setData(listModel: List<ModelClass>) {
data.clear()
data.addAll(listModel)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemViewBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return ViewHolder(binding, parent.context)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(data[position])
}
override fun getItemCount() = data.size
inner class ViewHolder(
val binding: ItemViewBinding,
val context: Context
): RecyclerView.ViewHolder(binding.root) {
fun bindItems(model: ModelClass) = with(binding) {
/*
* Map Your data Here
* example: tvTitle.text = model.title
* */
when (checkedPosition) {
-1 -> {
clLayout.setBackgroundResource(0)
}
else -> when (checkedPosition) {
absoluteAdapterPosition -> {
clLayout.setBackgroundResource(R.drawable.bg_curved_grey)
}
else -> {
clLayout.setBackgroundResource(0)
}
}
}
root.setOnClickListener {
clLayout.setBackgroundResource(R.drawable.bg_curved_grey)
if (checkedPosition != absoluteAdapterPosition) {
notifyItemChanged(checkedPosition)
checkedPosition = absoluteAdapterPosition
}
// Handle the clicked item
onItemClicked.invoke(absoluteAdapterPosition)
}
}
}
}
here how you use it in Your Activity or fragment
private val recyclerViewAdapter: RecyclerViewAdapter by lazy {
//RecyclerViewAdapter(this::onClickedItem) you can call the function below like this or
//RecyclerViewAdapter { onClickedItem(it) } or
RecyclerViewAdapter { position ->
onClickedItem(position )
}
}
private fun onClickedItem(position: Int) {
//do something
Toast.makeText(this, position.toString, Toast.LENGTH_SHORT).show()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.recyclerview.apply {
layoutManager = LinearLayoutManager(this)
adapter = recyclerViewAdapter
}
// yourdata = dataList:ArrayList<ModelClass>
recyclerViewAdapter.setData(yourData)
}
some explanation
its a Higher order function, you can read it more here Higher order function
val onItemClicked: (Int) -> Unit
with this piece of code we can remove this
private lateinit var nListener : onItemClickListener
interface onItemClickListener{
fun onItemClick(position: Int)
}
fun setOnItemClickListener(listener:onItemClickListener){
nListener=listener
}
with this piece of code
fun setData(listModel: List<ModelClass>) {
data.clear()
data.addAll(listModel)
notifyDataSetChanged()
}
we make the adapter flexible with any data set List<ModelClass>
Answered By - Rio Wirawan
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.