I am trying to display data from my Room database on RecyclerView, it works fine except when I fill in new data and try to update my RecyclerView it doesn't update. Here's part of the code that I tried using:
MainActivity.kt
val adapter = MainAdapter(myData)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
MainAdapter.kt
fun refresh(data: List<NewList>) {
val currentList: MutableList<MyList> = mutableListOf()
currentList.clear()
currentList.addAll(data)
notifyDataSetChanged()
}
I am trying to call this function from Fragment file so it can pass updated list from Room Database (It updates list once someone opens that fragment)
Fragment.kt
var myData = App.instance.db.getAllDao().getAll()
val adapter = MainAdapter(myData)
adapter.refresh(myData)
I printed updated list in the updateData() function and it does show updated list, as well as tried printing ItemCount and it also shows updated ItemCount, but does not update actual display with new data.
The adapter attached to the RecyclerView in MainActivity and in fragment are not same.
just delete adapter creation in Fragment and pass RecyclerView instance to Fragment and then set layout manager and adapter there instead of activity. lastly call updateData method in order to be able to populate adapter.
Related
val recyclerView = findViewById<RecyclerView>(R.id.rv)
val adapter = UserDetailsAdapter(users)
recyclerView.adapter =adapter
recyclerView.layoutManager= LinearLayoutManager(this)
Thread{
userDao.insertAll(user,user2,user3)
users= userDao.getAll() as ArrayList
Log.d("Checking Service",users.size.toString())
recyclerView.post {
Log.d("Checking Service","Data set Changed")
adapter.notifyDataSetChanged()
}
}.start()
Here recycler view in the UI does not updating the items .
runOnUIThread also tried but not working.
kindly explain why notify data set changed not working. and tell me how to update recycler view adapter from another thread.
You need to update the users data inside the adapter before actually calling notifyDataSetChanged().
In your case you need to update the data source which you initialised in adapter constructor .
add this function to your adapter instead of calling notify adapter change from activity
fun updateAdapter(users: ArrayList<User>) {
this.users= users
notifyDataSetChanged()
}
and call this function
adapter.updateAdapter(users)
I have a message list that contains messages. And I used a regular RecyclerView.Adapter instead of ListAdapter.
ChatFragment
chatViewModel.msgListDisplayLiveData.observe(viewLifecycleOwner, {
chatAdapter.setChat(it)
})
Here is the function to update messageList in adapter.
ChatAdapter
fun setChat(newMessages: List<Message>) {
val diffUtil = ChatDiffUtil(messageList, newMessages)
val diffResults = DiffUtil.calculateDiff(diffUtil)
messageList = newMessages
diffResults.dispatchUpdatesTo(this)
--> Method of using notifyDataSetChanged()
// messageList = newMessages
// notifyDataSetChanged()
}
Previously I am using notifyDataSetChanged() and the list item can be updated instantly, but without any animation.
Thus, I decided to use DiffUtils() and I got the nice animation when my list's item got append/remove.
However, when I want to update one of the item, DiffUtils seems do not have any visible effect.
Using notifyDataSetChanged() - can instantly update the row.
Using DiffUtils() - cannot update instantly.
What had I done wrongly? Please advise me.
now I find a bug in my project
val diffCallback = diff.newInstance(list, newList)
val diffResult = DiffUtil.calculateDiff(diffCallback)
list.clear()
list.addAll(newList)
diffResult.dispatchUpdatesTo(this)
this is my diff code in my adapter, you can see I clear old list and update the new list.
but I use data in viewholder and set tag with it in a view.
when I set old data as a tag in a view, then I diff the list, because as this diffUtil return true, so view also handler old data in his tag, but I always update adapter list when diff, so when I use adapter.list.getindex(data) I get -1 because view tag is old data, and my adapter list had to update new list, Even if the old list data view == new list.
when I remove list.clear() list.addAll(newList), the diff cannot succeed,
someone can tell me why? and how can I solve this problem?
override fun setAdapter() {
adapter = WaybillAdapter(items, activity!!, this, recyclerView)
recyclerView.adapter = adapter
}
I am updating my adapter when I should add items for my recycler like
override fun addWaybills(list: ArrayList<Data>) {
items.addAll(list)
adapter.setLoaded(true)
}
Add my position of an recycler is jumping to start.
My question is how should update adapter by not changing current position?
In your activitie's onCreate or fragment's onCreateView create initialize your adapter with empty ArrayList and later when you fetch your data add items to your arraylist and call adapter.notifyDataSetChanged()
I have DAO method returned LiveData<List<Category>>:
LiveData<List<Category>> listLiveData = categoryDao.getAll();
After that I need set this data to my Adapter:
listLiveData.observe(this, categories -> {
if (categories == null || categories.isEmpty()) {
price.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.INVISIBLE);
} else {
categoryAdapter = new CategoryAdapter(categories);
categoryAdapter.setOnItemClickListener(new ClickHandler());
recyclerView.setAdapter(categoryAdapter);
}
});
if I have not data in DB I show button for update(get data from server and insert to DB).
if I have data I create adapter and set data to it.
After that if I insert some Category to DB I get this:
triggered observe method and get all categories
create new adapter with this data
I think it is very bad practice(create a new adapter for update each item) and I can some way:
Change my adapter and add method addData(List<Category> categories);
in onCreateView I create adapter: categoryAdapter = new CategoryAdapter(new ArrayList());
then when I get data in observe method I add it to adapter:
adapter.addData(categories);
and into addData method in loop check each item and if not exist add to list and notify data.
change method
LiveData> listLiveData = categoryDao.getAll();
to
LiveData<Category> category = categoryDao.getLast();
and add this item to observe method. But I have 2 problems: 1 - How can I add firstly all data? I must implement 2 methods getAll(call wen create adapter) and getLast(call for each insert in DB). 2. How can I write this getLast method?
correct way that you will advise me :)
Your first step is right, you should create adapter only once in a lifecycle of Fragment or Activity and set the value(list) to adapter whenever you need to change dataset.
You should use getAll() method and it is best practice because you have data in local database and that doesn't take longer. If you have long data set then you should use pagination where only limited no. of items are fetched at a time. That can be achieved using LIMIT clause queries in sqlite.
And then use notifyDatasetChanged() method. If you want to show a smooth animation for newly inserted items use DiffUtil class to compare list and notify adapter accordingly.
To know how to use DiffUtil, check this out https://medium.com/#iammert/using-diffutil-in-android-recyclerview-bdca8e4fbb00
Hope this helps.