3

I'm not able to recreate this crash with my Pixel4XL, but it's occuring a lot in the past days. I cannot find out something that the devices on which it is crashing have in common. I'm glad that I implemented Crashlytics before. Thanks to the custom logs I can see that the crash occurs right after loading the list items without the user needing to touch one of them. The Recylcerview is quite big with 188 items in it.

Crashlytics is showing me this error: (Its highlighting the "measure(View.java:24534)" )

Fatal Exception: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionb{dea9ecf position=3 id=-1, oldPos=-1, pLpos:-1 no parent} androidx.recyclerview.widget.RecyclerView{5ad1f77 VFED.V... ......ID 0,510-1080,741 #7f09015f app:id/recylcerViewItems}, adapter:c.b.a.b@f609fb4, layout:androidx.recyclerview.widget.LinearLayoutManager@60507dd, context:com.blazecode.scrapguide.MainActivity@eeef29e
   at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:35)
   at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3)
   at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:3)
   at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java)
   at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:2)
   at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:22)
   at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:38)
   at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:61)
   at android.view.View.measure(View.java:24534)
   at androidx.constraintlayout.widget.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:69)
   at android.view.View.measure(View.java:24534)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
   at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
   at android.view.View.measure(View.java:24534)
   at androidx.constraintlayout.widget.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:69)
   at android.view.View.measure(View.java:24534)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
   at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
   at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:154)
   at android.view.View.measure(View.java:24534)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
   at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
   at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
   at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
   at android.view.View.measure(View.java:24534)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
   at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
   at android.view.View.measure(View.java:24534)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
   at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
   at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
   at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
   at android.view.View.measure(View.java:24534)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
   at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
   at com.android.internal.policy.DecorView.onMeasure(DecorView.java:742)
   at android.view.View.measure(View.java:24534)
   at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3007)
   at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1834)
   at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2123)
   at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1722)
   at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7605)
   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1041)
   at android.view.Choreographer.doCallbacks(Choreographer.java:864)
   at android.view.Choreographer.doFrame(Choreographer.java:799)
   at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1026)
   at android.os.Handler.handleCallback(Handler.java:883)
   at android.os.Handler.dispatchMessage(Handler.java:100)
   at android.os.Looper.loop(Looper.java:214)
   at android.app.ActivityThread.main(ActivityThread.java:7397)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

This is my ItemListAdapter.java:

public class ItemListAdapter extends RecyclerView.Adapter<ItemListAdapter.ItemViewHolder> implements Filterable {

private Context mContext;

private ArrayList<Item> mItemList;
private ArrayList<Item> mItemListFiltered;

private ItemsListAdapterListener mItemsListAdapterListener;

final Runtime runtime = Runtime.getRuntime();
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;

static double imgSize100 = 0.4;
static double imgSize75 = 0.3;
static double imgSize50 = 0.1;
static double imgSize10 = 0.01;

boolean ramShortageToastShown = false;


public ItemListAdapter(ArrayList<Item> itemArrayList, ItemsListAdapterListener itemsListAdapterListener, Context context) {

    mItemList = itemArrayList;
    mItemListFiltered = itemArrayList;
    mContext = context;
    this.mItemsListAdapterListener = itemsListAdapterListener;

}


public interface ItemsListAdapterListener {
    void onItemClick(Item item);
}



public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    public ImageView mImageView;
    public TextView mTextView;


    ItemsListAdapterListener mItemsListAdapterListener;

    public ItemViewHolder(@NonNull View itemView, ItemsListAdapterListener itemsListAdapterListener) {
        super(itemView);


        mItemsListAdapterListener = itemsListAdapterListener;

        mImageView = itemView.findViewById(R.id.imageViewItem);
        mTextView = itemView.findViewById(R.id.textViewItem);

        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        mItemsListAdapterListener.onItemClick(mItemListFiltered.get(getAdapterPosition()));
        //Log.i("test", "Adapter click");
    }

}


@NonNull
@Override
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_layout, parent, false);
    ItemViewHolder itemViewHolder = new ItemViewHolder(view, mItemsListAdapterListener);
    return  itemViewHolder;

}

@Override
public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {
    Item item = mItemListFiltered.get(position);

    long imgSize = availHeapSizeInMB / mItemList.size();

    if(imgSize == 0 && !ramShortageToastShown){
        Toast.makeText(mContext, mContext.getString(R.string.images_diabled_ram), Toast.LENGTH_SHORT).show();
        ramShortageToastShown = true;
    }

    Log.i("size", imgSize + "");
    if(imgSize > imgSize100){
        holder.mImageView.setImageBitmap(compressBitmap(item.getImgURL(), 100,100));
        Log.i("size", 100 + "%");
    } else if (imgSize > imgSize75){
        holder.mImageView.setImageBitmap(compressBitmap(item.getImgURL(), 75,75));
        Log.i("size", 75 + "%");
    } else if (imgSize > imgSize50){
        holder.mImageView.setImageBitmap(compressBitmap(item.getImgURL(), 50,50));
        Log.i("size", 50 + "%");
    } else if (imgSize > imgSize10){
        holder.mImageView.setImageBitmap(compressBitmap(item.getImgURL(), 10,10));
        Log.i("size", 10 + "%");
    } else {
        holder.mImageView.setVisibility(View.GONE);
        Log.i("size", "disabled");
    }


    holder.mTextView.setText(item.getItemName());

}

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {
            String charString = charSequence.toString();
            if (charString.isEmpty()) {
                mItemListFiltered = mItemList;
            } else {
                ArrayList<Item> filteredList = new ArrayList<>();
                for (Item row: mItemList) {

                    // name match condition. this might differ depending on your requirement
                    // here we are looking for name or phone number match
                    if (row.getItemName().toLowerCase().contains(charString.toLowerCase()) || row.getItemCategory().toLowerCase().contains(charString.toLowerCase())) {

                        filteredList.add(row);

                    }
                }

                mItemListFiltered = (ArrayList<Item>) filteredList;
            }

            FilterResults filterResults = new FilterResults();
            filterResults.values = mItemListFiltered;
            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            mItemListFiltered = (ArrayList<Item>) filterResults.values;

            ItemsFragment itemsFragment = new ItemsFragment();
            if(itemsFragment.isShowFilteredResultsEnabled()){
            notifyDataSetChanged();
            }

        }
    };
}

@Override
public int getItemCount() {
    return mItemListFiltered.size();
}





public Bitmap compressBitmap(int imgsrc, int width, int height){

    Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), imgsrc);

    BitmapFactory.Options options=new BitmapFactory.Options();
    Bitmap resized = Bitmap.createScaledBitmap(bitmap, width, height, true);

    return resized;
}
}

This is a cut version of the ItemFragment.java:

 final ArrayList<Item> itemArrayList = new ArrayList<>();
    addItems(itemArrayList);



    mRecyclerView = root.findViewById(R.id.recylcerViewItems);
    mRecyclerView.setHasFixedSize(true);
    mLayoutManager = new LinearLayoutManager(getContext());
    mAdapter = new ItemListAdapter(itemArrayList, this, getContext());

    mRecyclerView.setLayoutManager(mLayoutManager);
    mRecyclerView.setAdapter(mAdapter);

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            if(newState == RecyclerView.SCROLL_STATE_IDLE){
                if(!showFilteredResults) {
                    showFilteredResults = true;
                }
            } else {
                if(showFilteredResults) {
                    showFilteredResults = false;
                }
            }
            super.onScrollStateChanged(recyclerView, newState);
        }

        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
        }
    });

public void addItems(ArrayList<Item> itemArrayList){
         Item item_scrap_stone_block = new Item(getResources().getString(R.string.item_scrap_stone_block), R.drawable.item_scrap_stone_block, getString(R.string.item_blocks), null, 6, 3, 6, 5, false,
            null, 0, null, 0,
            null, 0, null, 0, getString(R.string.scrap_stone_origin));

itemArrayList.add(item_scrap_stone_block);
FirebaseCrashlytics.getInstance().log("Items Fragment added Items");
//here are 187 more items, this is just to show how it works
}


@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

    mRecyclerView.setScrollY(0);
    if(showFilteredResults) {
        mAdapter.getFilter().filter(s);
    } else {
        Toast.makeText(getActivity(),getString(R.string.please_try_again), Toast.LENGTH_SHORT).show();
    }
}

public boolean isShowFilteredResultsEnabled(){
    return showFilteredResults;
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void afterTextChanged(Editable s) {

    mRecyclerView.scrollToPosition(0);
    if(mAdapter.getItemCount() == 0){
        mRecyclerView.setVisibility(View.GONE);
        constraintLayoutMissingItem.setVisibility(View.VISIBLE);
    } else {
        mRecyclerView.setVisibility(View.VISIBLE);
        constraintLayoutMissingItem.setVisibility(View.GONE);
    }
}


@Override
public void onItemClick(Item item) {
    FirebaseCrashlytics.getInstance().log("Clicked " + item.getItemName() + " " + item.getItemCategory() + " " + item.getImgURL());

    dialog_itemInfo(getActivity(), item);
}

Item.java:

public class Item {

private String ItemName;
private int ImgURL;
private String ItemCategory;
private String ItemDescription;
private int Weight;
private int Durability;
private int Friction;
private int Buoyancy;
private boolean Flammable;

Item ItemCrafting1;
Item ItemCrafting2;
Item ItemCrafting3;
Item ItemCrafting4;

int ItemCrafting1Amount;
int ItemCrafting2Amount;
int ItemCrafting3Amount;
int ItemCrafting4Amount;

String ExtraInfo;

public Item(String itemName, int imgURL, String itemCategory, String itemDescription, int weight, int durability, int friction, int buoyancy, boolean flammable,
            Item itemCrafting1, int itemCrafting1Amount, Item itemCrafting2, int itemCrafting2Amount,
            Item itemCrafting3, int itemCrafting3Amount, Item itemCrafting4, int itemCrafting4Amount, String extraInfo) {

    ItemName = itemName;
    ImgURL = imgURL;
    ItemCategory = itemCategory;
    ItemDescription = itemDescription;
    Weight = weight;
    Durability = durability;
    Friction = friction;
    Buoyancy = buoyancy;
    Flammable = flammable;

    ItemCrafting1 = itemCrafting1;
    ItemCrafting2 = itemCrafting2;
    ItemCrafting3 = itemCrafting3;
    ItemCrafting4 = itemCrafting4;

    ItemCrafting1Amount = itemCrafting1Amount;
    ItemCrafting2Amount = itemCrafting2Amount;
    ItemCrafting3Amount = itemCrafting3Amount;
    ItemCrafting4Amount = itemCrafting4Amount;

    ExtraInfo = extraInfo;
}

public String getItemName() {
    return ItemName;
}

public void setItemName(String itemName) {
    ItemName = itemName;
}

public int getImgURL() {
    return ImgURL;
}

public void setImgURL(int imgURL) {
    ImgURL = imgURL;
}

public String getItemCategory() {
    return ItemCategory;
}

public void setItemCategory(String itemCategory) {
    ItemCategory = itemCategory;
}

public String getItemDescription() {
    return ItemDescription;
}

public void setItemDescription(String itemDescription) {
    ItemDescription = itemDescription;
}

public int getWeight() {
    return Weight;
}

public void setWeight(int weight) {
    Weight = weight;
}

public int getDurability() {
    return Durability;
}

public void setDurability(int durability) {
    Durability = durability;
}

public int getFriction() {
    return Friction;
}

public void setFriction(int friction) {
    Friction = friction;
}

public int getBuoyancy() {
    return Buoyancy;
}

public void setBuoyancy(int buoyancy) {
    Buoyancy = buoyancy;
}

public boolean isFlammable() {
    return Flammable;
}

public void setFlammable(boolean flammable) {
    Flammable = flammable;
}

public Item getItemCrafting1() {
    return ItemCrafting1;
}

public void setItemCrafting1(Item itemCrafting1) {
    ItemCrafting1 = itemCrafting1;
}

public Item getItemCrafting2() {
    return ItemCrafting2;
}

public void setItemCrafting2(Item itemCrafting2) {
    ItemCrafting2 = itemCrafting2;
}

public Item getItemCrafting3() {
    return ItemCrafting3;
}

public void setItemCrafting3(Item itemCrafting3) {
    ItemCrafting3 = itemCrafting3;
}

public Item getItemCrafting4() {
    return ItemCrafting4;
}

public void setItemCrafting4(Item itemCrafting4) {
    ItemCrafting4 = itemCrafting4;
}

public String getExtraInfo() {
    return ExtraInfo;
}

public void setExtraInfo(String extraInfo) {
    ExtraInfo = extraInfo;
}

public int getItemCrafting1Amount() {
    return ItemCrafting1Amount;
}

public void setItemCrafting1Amount(int itemCrafting1Amount) {
    ItemCrafting1Amount = itemCrafting1Amount;
}

public int getItemCrafting2Amount() {
    return ItemCrafting2Amount;
}

public void setItemCrafting2Amount(int itemCrafting2Amount) {
    ItemCrafting2Amount = itemCrafting2Amount;
}

public int getItemCrafting3Amount() {
    return ItemCrafting3Amount;
}

public void setItemCrafting3Amount(int itemCrafting3Amount) {
    ItemCrafting3Amount = itemCrafting3Amount;
}

public int getItemCrafting4Amount() {
    return ItemCrafting4Amount;
}

public void setItemCrafting4Amount(int itemCrafting4Amount) {
    ItemCrafting4Amount = itemCrafting4Amount;
}
}
BlazeCodeDev
  • 631
  • 1
  • 7
  • 27
  • 2
    Did you have a look at this SO post? It seems to be exactly your error: https://stackoverflow.com/questions/31759171/ – muetzenflo Jun 29 '20 at 16:51
  • Thanks for sharing, I know this post and already went through the solutions without any success. Specifically I tried to change "notifyDataSetChanged();" to "notifyItemRangeRemoved(0, oldSize);". This crashed with the same error message, but more often. Search terms which work in the first version would crash in the changed version. – BlazeCodeDev Jun 29 '20 at 17:21
  • 2
    @TimeLabsMedia You should really check that question again. The "I'm not able to recreate this crash" part sounds a lot like a threading issue, and the most voted answer there points to exactly that. – Mister Smith Jun 29 '20 at 20:32
  • I solved the androix problem. I have deleted the comment about it. I managed to get the layoutmanager to work, but it just adds one item and not all of them – BlazeCodeDev Jun 30 '20 at 18:55
  • Nevermind, I think I fixed it. Thanks for sharing the post! – BlazeCodeDev Jun 30 '20 at 19:36
  • If you have fixed it, please share the answer – M D P Jul 06 '20 at 09:52
  • The most upvoted answer from the shared post above is the answer. Just be cafeful with the LinearLayoutManager.HORIZONTAL, you may need vertical. – BlazeCodeDev Jul 06 '20 at 15:45

0 Answers0