Android ArrayIndexOutOfBoundsException and AbsListViewRecycleBin.addScrapView

I have an ArrayIndexOutOfBoundsException that accidentally appears. This seems to be happening during my notifyDataSetChanged(); . Because the error is so random, it makes it difficult to pinpoint exactly where it happens.

Adaptor anyone had problems with custom Adaptor ?

 FATAL EXCEPTION: main java.lang.ArrayIndexOutOfBoundsException: length=12; index=12 at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:8041) at android.widget.ListView.layoutChildren(ListView.java:1604) at android.widget.AbsListView.onLayout(AbsListView.java:2444) at android.view.View.layout(View.java:15221) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531) at android.widget.LinearLayout.onLayout(LinearLayout.java:1440) at android.view.View.layout(View.java:15221) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:15221) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:15221) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:15221) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531) at android.widget.LinearLayout.onLayout(LinearLayout.java:1440) at android.view.View.layout(View.java:15221) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:15221) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2260) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2007) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1249) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6364) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791) at android.view.Choreographer.doCallbacks(Choreographer.java:591) at android.view.Choreographer.doFrame(Choreographer.java:561) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777) at android.os.Handler.handleCallback(Handler.java:730) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5455) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:525) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) at dalvik.system.NativeStart.main(Native Method) public class CarUpfitScanvinadapter extends BaseAdapter{ @SuppressWarnings("unused") private final String TAG = this.getClass().getSimpleName(); private Activity mActivity; private ArrayList<CarUpfitModel> mData; private static LayoutInflater sInflater = null; public int height = 0; public int heightSet = 0; private CarUpfitModelForm mForm; private ScanlistListener mCallback; public CarUpfitScanvinadapter(Activity a, ArrayList<CarUpfitModel> d, Resources resLocal){ mActivity = a; mData = d; sInflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public void removeItem(int i){ mData.remove(i); this.notifyDataSetChanged(); } @Override public int getCount() { Log.v(TAG, "getCount"); if(mData.size()<=0) return 1; return mData.size(); } @Override public boolean hasStableIds (){ return false; } @Override public int getViewTypeCount() { return getCount(); } @Override public CarUpfitModel getItem(int position) { return mData.get(position); } @Override public int getItemViewType(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View vi = convertView; if(convertView == null){ vi = sInflater.inflate(R.layout.subaruupfitscanlistview, parent, false); mForm = new CarUpfitModelForm(); mForm.setllScanlist((LinearLayout) vi.findViewById(R.id.llScanlist)); mForm.getllScanlist().setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,heightSet)); mForm.setllheightset((LinearLayout) vi.findViewById(R.id.llheightset)); mForm.setetModel((EditText) vi.findViewById(R.id.etModel)); mForm.settvScanlistvin((TextView) vi.findViewById(R.id.tvScanlistvin)); mForm.settvScanlistdate((TextView) vi.findViewById(R.id.tvScanlistdate)); mForm.setcbGbkit((CheckBox) vi.findViewById(R.id.cbGbkit)); mForm.setcbFltmat((CheckBox) vi.findViewById(R.id.cbFltmat)); mForm.setcbFlmatbrk((CheckBox) vi.findViewById(R.id.cbFlmatbrk)); mForm.setcbEyesight((CheckBox) vi.findViewById(R.id.cbEyesight)); mForm.setcbTrnkpan((CheckBox) vi.findViewById(R.id.cbTrnkpan)); mForm.setcbIntmirror((CheckBox) vi.findViewById(R.id.cbIntmirror)); mForm.setcbExtmirror((CheckBox) vi.findViewById(R.id.cbExtmirror)); mForm.setcbPzevbadge((CheckBox) vi.findViewById(R.id.cbPzevbadge)); mForm.setivDelete((ImageView) vi.findViewById(R.id.ivDelete)); mForm.setivSave((ImageView) vi.findViewById(R.id.ivSave)); mForm.getivSave().setTag(mForm); vi.setTag(mForm); }else{ mForm = (CarUpfitModelForm) vi.getTag(); } mForm.getllScanlist().setOnClickListener(new OnItemClickListener(position, CarUpfit.ITEM_CLICK)); if(mData.size()<=0){ mForm.puttvScanlistvin("No Data"); }else{ mForm.puttvScanlistvin(getItem(position).getVin()); mForm.puttvScanlistdate(getItem(position).getDate()); mForm.setId(getItem(position).getid()); mForm.putjson(getItem(position).getData()); mForm.getivSave().setOnClickListener(new OnItemClickListener(position, CarUpfit.ITEM_UPDATE)); mForm.getivDelete().setOnClickListener(new OnItemClickListener(position, CarUpfit.ITEM_REMOVE)); } return vi; } private class OnItemClickListener implements OnClickListener{ private int mPosition; private int mType; OnItemClickListener(int position, int type){ mPosition = position; mType = type; } @Override public void onClick(View v) { mCallback.scanlistclick(v, mPosition, mType); } } public void setimplements(CarUpfit sl) { try { mCallback = (ScanlistListener) sl; } catch (ClassCastException e) { throw new ClassCastException("CarUpfit must implement ScanlistListener"); } } public interface ScanlistListener{ public void scanlistclick(View v, int position, int type); } } 

edits

I have a list of elements with animations that expand the elements of a list. so I have overrides on getViewTypeCount (). If I do not redefine it when the user opens the item, it will also open others.

Screenshot of closed objects:

items closed

Screenshot:

enter image description here

+7
java android arraylist indexoutofboundsexception
source share
3 answers

You should not override getViewTypeCount() and getItemViewType() if all items in the list are uniform or at least return them 1 and 0 respectively.

Redefining them the way you did, first of all, you prohibit the ListView relational processing mechanism, and secondly, it probably leads to the collapse described by you, because when you delete an item from the middle of the list, the types from the views change after deletion .

UPDATE: Actually, this is what happens: ListView calls getViewTypeCount() on the adapter only in setAdapter() and creates an internal array of this size. Therefore, if you add views later, and your getItemViewType() returns an index greater than or equal to this size, you will get an ArrayIndexOutOfBoundsException .

UPDATE 2:. If you need a list extension just use the ExpandableListView .

UPDATE 3: Well, I will explain as much as possible.

There is no reason to open screen views. ListView designed to be recycled and inhibited, it is not needed in 99.9% of cases, and your case does not drop to 0.01%.

Your adapter should remember all the details and populate the reappearing views when scrolling through the ListView.

In your case, you have two types of views - open and closed, so getViewTypeCount() should return 2, and getItemViewType() should return 0 or 1 depending on whether the view is closed or open.

In getView() , if convertView is null, you should create it depending on what getItemViewType() returns for this position. And if it's not null, you are guaranteed that this is one of the views that you created earlier for the same type.

And here is the point of failure that occurs if your getItemViewType() returns arbitrary large numbers (I mean the sources for API 19):

 // ListView.java public void setAdapter(ListAdapter adapter) { ... // This is the only call to getViewTypeCount() mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); ... } // AbsListView.java public void setViewTypeCount(int viewTypeCount) { ... // Here it creates the array of given size ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount]; ... mViewTypeCount = viewTypeCount; mScrapViews = scrapViews; } void addScrapView(View scrap, int position) { final int viewType = lp.viewType; ... // And here you get ArrayIndexOutOfBoundsException mScrapViews[viewType].add(scrap); } 
+14
source share

You think that an index outside occurs with a change in the notification dataset. I agree. For example, when you delete an item. All listeners for clicking on an element after this element will have the wrong mposposition value.

0
source share

This also happens when your getItemViewType returns integers that exceed the size of getViewTypeCount, so they look like indexes. For example. getViewTypeCount 2 requires getItemViewType 0 and 1.

0
source share

All Articles