Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crash: java.lang.IllegalStateException in android.widget.ListView.layoutChildren

I have crashes in prod that I can't reproduce. The trace does not say where it crashes. After making some searches it looks like it could be related to notifyDataSetChanged(). It happens on Android 6 and 7.

I have 2 packages where I use listview:

A BroadcastReceiver to check the list of wifi APs: in this case the code collects all the APs, adds them in a List and calls notifyDataSetChanged:

 @Override
    public void onReceive(Context context, Intent intent) {
        if (wifiManager != null) {
            if (wifiManager.isWifiEnabled()) {
                List<ScanResult> listeScan = wifiManager.getScanResults();
                listeWifiItem.clear();
                for (ScanResult scanResult : listeScan) {
                    WifiItem item = new WifiItem();

                    item.setAdresseMac(scanResult.BSSID);
                    item.setAPName(scanResult.SSID);
                    item.setForceSignal(scanResult.level);

                    listeWifiItem.add(item);
                }

                wifiAdapter.notifyDataSetChanged();
            } else {
                Toast.makeText(context, "You must activate the WiFi", Toast.LENGTH_SHORT);
            }
        }
    }

And an async task in which I call notifyDataSetChanged in the method onPostExecute:

@Override
protected void onPostExecute(Void result) {
    iPadaptater.notifyDataSetChanged();
    super.onPostExecute(result);
}

Is there an issue with the way I use notifyDataSetChanged? In the async task, if the user moves to another function, I thought it was safer to do it

Do you think the crash is related to notifyDataSetChanged?

Do you see another important info from the traces?

Here are the 2 types of traces:

-type 1:

  java.lang.IllegalStateException: 
      at android.widget.ListView.layoutChildren (ListView.java:1747)
      at android.widget.AbsListView$CheckForTap.run (AbsListView.java:4728)
      at android.os.Handler.handleCallback (Handler.java:751)
      at android.os.Handler.dispatchMessage (Handler.java:95)
      at android.os.Looper.loop (Looper.java:154)
      at android.app.ActivityThread.main (ActivityThread.java:6776)
      at java.lang.reflect.Method.invoke (Native Method)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1520)
      at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1410)

-type 2:

java.lang.IllegalStateException: 
  at android.widget.ListView.layoutChildren (ListView.java:1623)
  at android.widget.AbsListView.onTouchUp (AbsListView.java:4210)
  at android.widget.AbsListView.onTouchEvent (AbsListView.java:3969)
  at android.view.View.dispatchTouchEvent (View.java:9957)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2705)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2386)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2711)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2400)
  at com.android.internal.policy.DecorView.superDispatchTouchEvent (DecorView.java:416)
  at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent (PhoneWindow.java:1837)
  at android.app.Activity.dispatchTouchEvent (Activity.java:3154)
  at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent (WindowCallbackWrapper.java:63)
  at com.android.internal.policy.DecorView.dispatchTouchEvent (DecorView.java:378)
  at android.view.View.dispatchPointerEvent (View.java:10177)
  at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent (ViewRootImpl.java:4634)
  at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:4502)
  at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3953)
  at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:4006)
  at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3972)
  at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3980)
  at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3953)
  at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:4006)
  at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3972)
  at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:4101)
  at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3980)
  at android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:4158)
  at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3953)
  at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:4006)
  at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3972)
  at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3980)
  at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3953)
  at android.view.ViewRootImpl.deliverInputEvent (ViewRootImpl.java:6443)
  at android.view.ViewRootImpl.doProcessInputEvents (ViewRootImpl.java:6417)
  at android.view.ViewRootImpl.enqueueInputEvent (ViewRootImpl.java:6378)
  at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent (ViewRootImpl.java:6577)
  at android.view.InputEventReceiver.dispatchInputEvent (InputEventReceiver.java:185)
  at android.os.MessageQueue.nativePollOnce (Native Method)
  at android.os.MessageQueue.next (MessageQueue.java:323)
  at android.os.Looper.loop (Looper.java:136)
  at android.app.ActivityThread.main (ActivityThread.java:6311)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:872)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:762)
like image 369
narb Avatar asked Oct 08 '17 08:10

narb


1 Answers

Looking at the source code for API 25, the only place that an illegal state exception is thrown is in LayoutChildren() of ListView. The exception states in the code:

Extract from ListView$LayoutChildren:

// Handle the empty set by removing all views that are visible
// and calling it a day
if (mItemCount == 0) {
    resetList();
    invokeOnItemScrollListener();
    return;
} else if (mItemCount != mAdapter.getCount()) {
    throw new IllegalStateException("The content of the adapter has changed but "
            + "ListView did not receive a notification. Make sure the content of "
            + "your adapter is not modified from a background thread, but only from "
            + "the UI thread. Make sure your adapter calls notifyDataSetChanged() "
            + "when its content changes. [in ListView(" + getId() + ", " + getClass()
            + ") with Adapter(" + mAdapter.getClass() + ")]");
}

This indicates that there is a mismatch between the internal item count maintained by ListView and the item count maintained by the adapter. It looks like LayoutChildren is probably being called from the CheckforTap inner class of AbsListView:

Extract from AbsListView$CheckforTap:

if (!mDataChanged) {
    final float[] point = mTmpPoint;
    point[0] = x;
    point[1] = y;
    transformPointToViewLocal(point, child);
    child.drawableHotspotChanged(point[0], point[1]);
    child.setPressed(true);
    setPressed(true);
    layoutChildren();
    // ... and it continues...

This is probably why others are asking if you are changing the data set from a non-UI thread. It also seems to point to a potential issue with how you are calling notifyDataSetChanged().

Assuming that you are using the UI thread for the changes and without knowing more about the internal workings of your app, I can just suggest that you not separate the call to notifyDataSetChanged() from the changes that you are making. You appear to do so from your responses.

like image 94
Cheticamp Avatar answered Sep 25 '22 18:09

Cheticamp