HelloCW
HelloCW

Reputation: 2255

How to rebind item in RecyclerView when the data changed in Kotlin?

I customize a RecyclerView class which will display the content of val backupItemList: List<MSetting> in Kotlin in Code B

Now I modify the data of backupItemList outside RecyclerView class, I think the Code D will display the latest data in UI, but I failed, the UI is still to display old data. I have to use Code C to display the latest data.

What's wrong with the Code D?

Code A

class UIMain : AppCompatActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.layout_main)                       

        allList= SettingHandler().getListAllSetting()            

        mRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
        mCustomAdapter= CustomAdapter(allList)
        mRecyclerView.adapter= mCustomAdapter


   }


   public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
       //Code C          
       if (resultCode == RESULT_OK) {
           allList=SettingHandler().getListAllSetting()
           mCustomAdapter= CustomAdapter(allList)
           mRecyclerView.adapter= mCustomAdapter
           mCustomAdapter.notifyDataSetChanged()
           mCustomAdapter.setSelectedItem(selectedBackupItem)  
       }


       //Code D     
       if (resultCode == RESULT_OK) {
          allList=SettingHandler().getListAllSetting()                
          mCustomAdapter.setSelectedItem(selectedBackupItem)                
       }         

   }        

}

Code B

  class CustomAdapter (val backupItemList: List<MSetting>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

        val noRecord=-1
        private var mSelectedItem = noRecord

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
            val v = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview, parent, false)
            return ViewHolder(v)
        }

        fun getSelectedItem():Int{
            return  mSelectedItem
        }

        fun setSelectedItem(index:Int){
            if (index in 0..(backupItemList.size-1) ){
                mSelectedItem=index
                notifyDataSetChanged();
            }

        }

        override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
            holder.bindItems(backupItemList[position])
        }

        override fun getItemCount(): Int {
            return backupItemList.size
        }

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

            fun bindItems(aMSetting: MSetting) {
                itemView.tvSubject.text=aMSetting.name
                itemView.tvCreatedDate.text=aMSetting.createdDate.toDateString()
                itemView.tvDescription.text=aMSetting.description   
                itemView.radioButton.setOnClickListener {
                mSelectedItem=adapterPosition
                notifyDataSetChanged();
            }

            if(adapterPosition == 0 && mSelectedItem == noRecord) {             
                itemView.radioButton.isChecked = true
                mSelectedItem=adapterPosition
            }
            else {
                itemView.radioButton.isChecked =(adapterPosition == mSelectedItem)
            }       
            }

        }

    }

To civic.LiLister:

Both Code C And Code D get the same result if I use Code E (I replace val with var),why?

Code E

  class CustomAdapter (var backupItemList: List<MSetting>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

        val noRecord=-1
        private var mSelectedItem = noRecord

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
            val v = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview, parent, false)
            return ViewHolder(v)
        }

        fun getSelectedItem():Int{
            return  mSelectedItem
        }

        fun setSelectedItem(index:Int){
            if (index in 0..(backupItemList.size-1) ){
                mSelectedItem=index
                notifyDataSetChanged();
            }

        }

        override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
            holder.bindItems(backupItemList[position])
        }

        override fun getItemCount(): Int {
            return backupItemList.size
        }

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

            fun bindItems(aMSetting: MSetting) {
                itemView.tvSubject.text=aMSetting.name
                itemView.tvCreatedDate.text=aMSetting.createdDate.toDateString()
                itemView.tvDescription.text=aMSetting.description   
                itemView.radioButton.setOnClickListener {
                mSelectedItem=adapterPosition
                notifyDataSetChanged();
            }

            if(adapterPosition == 0 && mSelectedItem == noRecord) {             
                itemView.radioButton.isChecked = true
                mSelectedItem=adapterPosition
            }
            else {
                itemView.radioButton.isChecked =(adapterPosition == mSelectedItem)
            }       
            }

        }

    }

Upvotes: 8

Views: 11388

Answers (7)

Shweta Chauhan
Shweta Chauhan

Reputation: 6981

In your Activity onCreate method

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.layout_main)                
    
            allList = ArrayList< MSetting>()
            mCustomAdapter = CustomAdapter(mChildList)
            mRecyclerView.layoutManager = LinearLayoutManager(context)
            mRecyclerView.adapter = mCustomAdapter
    }

Now in onActivityResult

     public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {

           //Code C          
           if (resultCode == RESULT_OK) {
              if(data != null){
                 allList.clear()
                 allList.addAll(SettingHandler().getListAllSetting())
                 mCustomAdapter.notifyDataSetChanged()
                 mCustomAdapter.setSelectedItem(selectedBackupItem) 
              } 
           }
        
      }        

Upvotes: 6

trinadh thatakula
trinadh thatakula

Reputation: 923

yourAdapter().notifyDataSetChanged

Upvotes: 1

civic.LiLister
civic.LiLister

Reputation: 2197

The secret maybe hide here:

class CustomAdapter (val backupItemList: List)

When you init an instance of CustomAdapter, the value is copied to property backupItemList, rather than assigned the reference. Therefore, when you change property allList of UIMain, the backupItemList won't change as you expected.

The solution is simple, as Ganesh Tikone wrote: add an method to update backupItemList.

fun updateData(data: List<MovieModel>) {
    backupItemList.clear()
    backupItemList.addAll(data)
    notifyDataSetChanged()
}

and change Code D to:

//Code D     
   if (resultCode == RESULT_OK) {
      allList=SettingHandler().getListAllSetting()  
      mCustomAdapter.updateData(allList)    
      mCustomAdapter.setSelectedItem(selectedBackupItem)                
   }  

Have a try.

Upvotes: 7

Ganesh Tikone
Ganesh Tikone

Reputation: 1057

Fragment Code

private var adapter: RecentMovieAdapter? = null

Adapter is initialized in onCreateView method of fragment

adapter = RecentMovieAdapter(activity, this)

This is callback method in Fragment, which gets data from Server using Threading technique

override fun onDataReceived(randomDialog: List<MovieModel>) {
    shimmerView!!.stopShimmerAnimation()
    shimmerView!!.visibility = View.GONE
    adapter!!.updateData(randomDialog)
}

Adapter Class Code

private var movieList: MutableList<MovieModel> = mutableListOf<MovieModel>()

Add update function in Adapter class like this

fun updateData(data: List<MovieModel>) {
    movieList.clear()
    movieList.addAll(data)
    notifyDataSetChanged()
}

Upvotes: 2

AbdulAli
AbdulAli

Reputation: 555

In your code D, you are overwriting the reference for allList.

And the backupItemList in CustomAdapter has the reference for the same. So if you reassign the reference for allList the changes will not be picked up in recycler view

first make sure allList is mutable

val allList = mutableListOf<MSetting>()

then in code D

allList.clear()
allList.addAll(SettingHandler().getListAllSetting())
mCustomAdapter.notifyDataSetChanged()

Upvotes: 3

Rajan Kali
Rajan Kali

Reputation: 12953

The problem is you are not using any binding which means when you modify list, Adapter won't be aware of that hence it simply displays old items, but once you notify adapter about changes in your list using notifyDatasetChanged, it will try to refresh items with new data. If you want to achieve functionality with code D, you need to use Data Binding using Observable pattern.For more information RecyclerView and Data Binding

Upvotes: 2

Farhana Naaz Ansari
Farhana Naaz Ansari

Reputation: 7944

Check this code,

if (resultCode == RESULT_OK) {
           allList.clear()
           allList=SettingHandler().getListAllSetting()
           mCustomAdapter= CustomAdapter(allList)
           mRecyclerView.adapter= mCustomAdapter  
           mCustomAdapter.setSelectedItem(selectedBackupItem) 
       }

Upvotes: 2

Related Questions