Reputation: 69
I'm having a problem where I want to display a circular loading progress bar for when the recycler view is loading and only display recyler view when it is fully loaded, because when I search for an item in recycler view it crashes giving me the error:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 1(offset:1).state:8077 androidx.recyclerview.widget.RecyclerView{e6252d0 VFED....
The only way to not get the crash is to wait for around 4 seconds and scroll a little bit till it fully loads. And activity only opens when it can visibly display recycler view which also gives it a delay.
So how do I fix this error, maybe by displaying recycler view and search bar only after it is fully loaded?
private void getAllStocks() {
try {
String[] nasdaqLine;
String[] nyseLine;
while ((nasdaqLine = nasdaqReader.readNext()) != null){
nasdaqSymbol = nasdaqLine[0];
nasdaqFullName = nasdaqLine[1];
sector = nasdaqLine[5];
industry = nasdaqLine[6];
stocksList.add(new StocksList(nasdaqSymbol, nasdaqFullName, sector, industry));
}
while ((nyseLine = nyseReader.readNext()) != null){
nyseSymbol = nyseLine[0];
nyseFullName = nyseLine[1];
stocksList.add(new StocksList(nyseSymbol, "", nyseFullName, null));
}
} catch (IOException e) {
e.printStackTrace();
}
}
This is how I populate my recyler view.
getAllStocks();
layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
adapter = new StocksListAdapter(stocksList);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
if (stocksList.size() == 8893) {
adapter.notifyDataSetChanged();
circularProgressBar.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
And this is how I try to only show it after it fully loads but activity only opens after it can visibly display recycler view.
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String Key = charSequence.toString();
if (Key.isEmpty()){
stocksListFilterd = stocksList;
} else {
ArrayList<StocksList> listFiltered = new ArrayList<>();
for (StocksList stock : stocksList){
if (stock.getFullName().toLowerCase().contains(Key.toLowerCase()) || stock.getSymbol().toLowerCase().contains(Key.toLowerCase())
|| stock.getSector().toLowerCase().contains(Key.toLowerCase())){
listFiltered.add(stock);
}
}
stocksListFilterd = listFiltered;
}
FilterResults filterResults = new FilterResults();
filterResults.values = stocksListFilterd;
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
stocksListFilterd = (ArrayList<StocksList>) filterResults.values;
notifyDataSetChanged();
}
};
}
And this is the filter class in my adapter
Upvotes: 0
Views: 1099
Reputation: 69
Figured out how to fix error by another video and it is pretty much just a more simple Filter rewrite
Where I populate my recycler view all I did was add this
while ((nyseLine = nyseReader.readNext()) != null){
nyseSymbol = nyseLine[0];
nyseFullName = nyseLine[1];
stocksList.add(new StocksList(nyseSymbol, "", nyseFullName, null));
}
//I added this to set the adapter and show the list immediately after
//loading
adapter = new StocksListAdapter(stocksList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
Then I crated this method in The SAME activity not in the adapter class
private void Filter(String searched) {
for (StocksList stock : stocksList ){
if (stock.getSymbol().toLowerCase().equals(searched)){
//created new array list for the filter
filteredList.add(stock);
}
}
recyclerView.setAdapter(new StocksListAdapter(filteredList));
adapter.notifyDataSetChanged();
}
And this is the OnCreate class editText listener
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
searchStocks.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
//Moved the the stuff to afterTextChanged not onTextChanged
@Override
public void afterTextChanged(Editable editable) {
filteredList.clear();
if (editable.toString().isEmpty()){
recyclerView.setAdapter(new StocksListAdapter(stocksList));
adapter.notifyDataSetChanged();
} else {
Filter(editable.toString());
}
}
});
I'm pretty sure the error was the fact that I set all the recycler view values like recyclerview.setAdapter(new StocksListAdapter(stocksList)
in one method that I called once in the oncreate method
And when it needed to update the adapter with a new filtered list adapter.notifyDataSetChanged()
was unreachable and didn't do anything.
And so inside the adapter class it was working with inconsistent lists back and forth thus crashing. This is only my guess though, and the comment from @shagberg really helped.
P.S anyone else having this problem in the future: check your notifyDataSetChanged()
calls so they aren't after Filter
calls or other data changing methods because if it's called in the wrong place it crashes.
Upvotes: 1
Reputation: 2512
Is there a chance that the data that you are attempting to display in your RecyclerView is being modified in a different thread somewhere else? That would likely account for the Inconsistency detected
error message that you are seeing.
If you are filtering the data in the RecyclerView through a search, make sure that you call notifyDataSetChanged()
afterwards to refresh the data in the RecyclerView.
You don't show where you are calling getFilter()
, but it doesn’t appear to be using the notifyDataSetChanged()
within the publishResults()
method. Depending on how your code is structured, try calling notifyDataSetChanged()
where you return the data from return filterResults
.
Upvotes: 2