I have this kind of problem. I have a simple app for wallpapers.
I am getting wallpapers from API, there is a Tab called Category in which I have Sections I would like to hide few of that Sections inside Category Tab.
In the best scenario my backend developer have to hide or remove it from backend but as he is not available now. I have decided to do it myself.
So, in RecyclerView for Category Tab in onBindViewHolder I am checking if the title is equal the one that I want to be deleted I am calling removeAt (you can see that part below):
if (categoryTitle.equals("Hot")) {
list.removeAt(holder.layoutPosition)
}
I need this to be called whenever the Category Tab shows so the user will not be able to see that Category Section. But it doesn't update it because I have to call this two methods as well:
if (categoryTitle.equals("Hot")) {
list.removeAt(holder.layoutPosition)
notifyItemRemoved(holder.layoutPosition)
notifyItemRangeChanged(holder.layoutPosition, list.size)
}
but while call them I got en error saying
"Cannot call this method while RecyclerView is computing a layout or scrolling . . ."
Here is the question.
Where I have to call it to avoid the error ?
(link of my app:
https://play.google.com/store/apps/details?id=com.backpaper)
(please do not suggest to use timer or delay or something similar (-_-) )
Update:
override fun onResponse(categories: Categories) {
categories.categories!!.removeAt(5)
categories.categories!!.removeAt(1)
adapter = RecyclerViewAdapterC(categories.categories!!)}
Do not remove item in onBindViewHolder() It will throw exception because item is not added yet . Exception will be as.
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
You should remove the item from dataset before adding them to adapter .
if (!categoryTitle.equals("Hot")) {
// Add item else do not add item
}
After filtering the list dataset then set adapter with filtered list .
below is an example .
ArrayList<String> list=new ArrayList();
for(String cat : categories.categories){
if (!categoryTitle.equals("Hot")) {
list.add(cat);
}
}
adapter = RecyclerViewAdapterC(list)
Related
I have a button which clears the Arraylist that a RecyclerAdapter is using, but this causes the List to update even though I don't call .notifyDataSetChanged()
#OnClick(R.id.btn_search)
void onBtnSearchClick() {
String name = String.valueOf(searchView.getQuery()).trim();
if(name.equals("")){
return;
}
btnSearch.setClickable(false);
tvNoResults.setVisibility(View.GONE);
centerProgressBar.setVisibility(View.VISIBLE);
listUsers.clear(); //An ArrayList
Log.d(TAG, "onBtnSearchClick: " + listUsers.size());
}
Is this the expected behavior?
This is not related to RecyclerView at all . Its all about the Object reference .
Consider the code block below
ArrayList<String> list=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding.recylerView.setAdapter(new MyAdapter(list));
}
In this case if i use same ArrayList for showing data in MyAdapter i.e list . then it will be holding the same reference . and if any point of time i make any modification on list this will reflect in MyAdapters's list too because they Are pointing to same reference regardless of calling notifyDataSetChanged() .
this is why you have notify the adapter for any changes you made otherwise you will see weird behavior when you access the data item for any position and some times exception too like java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position.
Is this the expected behavior?
Yes, If you're passing an ArrayList to your Adapter, and you're adding elements in onCreate, that would be before the app has drawn your first frame.
There is a moment where you're able to add elements because the adapter hasn't laid out the items.
And within your onClick, that would be after onCreate has finished, which means the adapter is already laid out.
Because of this reason, it might be refreshing without .notifyDataSetChanged()
When I am using androidx ListAdapter with ViewPager2 and try to update the specific list item from fragment with adapter.notifyItemChanged, I have crash that shows java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling.
Previously I was using recyclerView and could resolve the crash by the condition with if(recyclerView.isComputingLayout()) before adapter.notifyItemChanged. Unfortunately ViewPager does not have method that returns computing information. Also, checking the stateScroll gives me nothing. Maybe someone had this problem before? Here's code:
viewModel.invoicePositionList.observe(viewLifecycleOwner, {
if (viewModel.currentInvoicePositionPosition >= 0) {
adapter.notifyItemChanged(viewModel.currentInvoicePositionPosition)
viewModel.currentInvoicePositionPosition = -1
} else {
adapter.submitList(it)
}
})
You are not expected to call notifyItemChanged when using ListAdapter. All you need is to create a new list without the removed item and call submitList.
I have this issue:
I'm using a recycler view in my app but the thing is that I need to update one single item of my recycler view.
When I click on the recycler view item, it sends me to another screen where I update the value and returned (this is working, I get the values on back)
I tried to add a new function inside my adapter as follows:
public fun updateItem(updatedOI: ArrayList<OrderItem>){
orderItem = updatedOI
notifyDataSetChanged()
}
and then call the function from my fragment/activity but it is not working.
I basically need to grab the index somehow and update that single index what it is doing now is removing all of the items and just add the updated one.
How do I fix this issue?
The problem is you can't update the data by making it reference another.
fun update(items: List<OrderItem>) {
orderItem.clear()
orderItem.addAll(items)
notifyDataSetChanged()
}
I'm using a list here because it is easier than working with arrays, your inner data should be a mutable list.
If you only want to update 1 item. You can get the index and then pass it back
//in the fragment/activity
intent.putExtra(INDEX, youClickedIndex)
and then set the result back like you are allegedly doing
fun update(item: OrdertItem, index: Int) {
orderItem.add(index, item)
notifyItemChanged(index)
}
picture from a reddit news feed
(https://i.stack.imgur.com/6YXMK.jpg)
I am creating an app with a list view that is populated from a sqlite database. Each of the data base items can have a status of either “resolved” or “unresolved”.
I want the listview to have 3 “tabs” with the labels “all items”, “resolved items”, and “unresolved items” with correspoding sqlite queries to populate each.
It should behave similarly to the one pictured.
I assumed this would be a tabbed listview and have been watching tutorials for a week based on those search words and it’s taking taking me down a dark rabbit hole of fragments and changing gradles and so on. I’m not sure tabs are what i really want.
Could I do this with three buttons instead where each button would run a different query and populate my listviewcontainer?
Ideally, when the page is opened, the first “tab” would be highlighted and the listview populated with all records. As the other tabs are pressed, they would highlight and a new query would run.
Would another approach work better?
I’m not asking for code, I just want some conceptual direction on where to focus my research.
If I get you right you need to filter your query results in different lists. Making a lot of queries into database is not the thing that is preferable specially if it's going to be a long process and doing it a lot of times is time and memory consuming.
So to make it work you could simple store your full query result in one variable and change the RecyclerView data using custom method setList() and later using notifyDataSetChanged() to apply the changes.
To make it work you need to get understanding of "how RecyclerView works" and then you will be fine.
So after providing the right logic you would be able to simple split your whole query result as it's needed (by element values for example) as it's showed above:
About the code below:
list - is your query result
leftFilterList or rightFilterList - are lists that contain sorted items
adapter.setList(rightFilterList) - sets the RecyclerView data (filtered items in our case)
adapter.notifyDataSetChanged() - is used to notify RecyclerView that list was changed, and he need to rebuild it.
So we have two Buttons and logic that fillter items in differend ways.
public void left(View view) {
ArrayList<ExampleItem> leftFilterList = new ArrayList<>();
for (ExampleItem item : list) {
if (item.getTitle().length() % 2 == 0) {
leftFilterList.add(item);
}
}
adapter.setList(leftFilterList);
adapter.notifyDataSetChanged();
}
public void right(View view) {
ArrayList<ExampleItem> rightFilterList = new ArrayList<>();
for (ExampleItem item : list) {
if (item.getTitle().length() % 2 == 1) {
rightFilterList.add(item);
}
}
adapter.setList(rightFilterList);
adapter.notifyDataSetChanged();
}
And the result of filtering*:
sorry for wrong toast text. It shows the whole list size.
I've read many of the previous posts on this topic, but i'm not getting it right.
I have an adapter which has a private values of the items in the list.
When i update the values(add a new items), i watch the value in debugger and the "getView" func and see that the value is correct.
BUT the actual rowView i see is just the first item in the list.
I have no clue what may cause this.
This listview is on the same activity while i show a different layout and hide the listview to add a new item.
Can there be a connection while the listview visibility is "GONE"?
When i remove items from it it updates listview fine(that is done when listview is visible).
private void updateAdapter() {
this.values.clear();
this.values.addAll(staticlistIndifferentclass);
notifyDataSetChanged();
}
~~~~UPDATE~~~~
Ok,
So i discovered the cause of the problem, though i'm not sure why it is.
The code was fine the way it was with regular Listview but the bug is on:
com.baoyz.swipemenulistview.SwipeMenuListView
Try use ListView.invalidateViews
This should cause views rebuilding
Use new Adapter object like this :
listView.setAdapter(new yourCustomAdapter());
When you delete all dataSet items ,it is better to bind new Adapter object .