我已经看到很多关于这个主题/错误的其他问题,但似乎没有一个在我的情况下。以下LogCat
与我的导航抽屉列表adapter
相关。
(LogCat
下面的简要代码)
java.lang.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(2131558613, class android.widget.ListView) with Adapter(class com.---.---.DrawerAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1572)
at android.widget.AbsListView.onTouchUp(AbsListView.java:3959)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:3758)
at android.view.View.dispatchTouchEvent(View.java:9349)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2240)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2559)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2260)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2559)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2260)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2559)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2260)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2559)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2260)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2559)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2260)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2559)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2260)
at com.android.internal.policy.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2453)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1755)
at android.app.Activity.dispatchTouchEvent(Activity.java:2776)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:67)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:67)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2402)
at android.view.View.dispatchPointerEvent(View.java:9590)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4436)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4292)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3816)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3875)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3841)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3971)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3849)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4028)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3821)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3875)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3841)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3849)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3821)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6150)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6118)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6072)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6253)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:216)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:5845)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:687)
在我onCreate()
的{{1}}内,我只是这样做:
MainActivity
我没有在此列表中添加任何内容。它改变的唯一时间是用户"升级"应用程序,然后我删除一个项目。
这是执行此操作的代码:
mDrawerList = (ListView) findViewById(R.id.drawer_list);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
String[] calcTypeList = new String[]{"item1", "item2", "etc".}; // 13 items total
// override with new list if user upgraded? (1 less item)
if (myApp.didUpgrade) {
calcTypeList = new String[]{"item1", "item2", "etc".}; // 12 items total
}
dAdapter = new DrawerAdapter(MainFragmentActivity.this, lcTypeList);
mDrawerList.setAdapter(dAdapter);
我想我一直在读你不想添加项目或在后台线程中执行notifyDataSetChanged()。不确定这是否是上面的后台线程?即使这样,我也不相信错误发生时会触发这个。 (但我不会完全打折)。
如果用户确实升级了,那么当应用程序启动时 - 由于升级菜单项是最后一项,我不再需要显示它,我只是这样做:
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result,
Purchase purchase) {
if (result.isFailure()) {
Log.i("Purchase Result", "There was a problem with the purchase: " + result.getMessage());
return;
} else if (purchase.getSku().equals(SKU_UPGRADE)) {
Toast.makeText(MainFragmentActivity.this, "Upgrade Successful!", Toast.LENGTH_SHORT).show();
MyApp.didUpgrade = true;
dAdapter.notifyDataSetChanged();
}
}
};
中的:
DrawerAdapter
我无法想到任何其他代码。
感谢所有反馈!
修改:
根据建议更新了代码。 @Override
public int getCount() {
if (MyApp.didUpgrade) {
return 12;
} else {
return 13;
}
}
的一个实例现在正被移动到UI线程。但是,只有在用户直接单击应用内购买和升级后才会调用此代码。我不相信它再次被召唤。出现此错误的用户每次进入应用程序时都会报告并单击菜单项。
notifyDataSetChanged()
更新#2
用户在最近的更新后报告了这个错误,我做过。该应用程序尚未更新9个月。我真正做的唯一改变就是从23开始查看targetSdkVersion - > 25.还要升级附加费。我不记得旧版本,新闻一个
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result,
Purchase purchase) {
if (result.isFailure()) {
Log.i("Purchase Result", "There was a problem with the purchase: " + result.getMessage());
return;
} else if (purchase.getSku().equals(SKU_UPGRADE)) {
Toast.makeText(MainFragmentActivity.this, "Upgrade Successful!", Toast.LENGTH_SHORT).show();
MyApp.didUpgrade = true;
setDrawerAdapter();
}
}
};
private void setDrawerAdapter() {
new Thread() {
public void run() {
try {
runOnUiThread(new Runnable() {
@Override
public void run() {
dAdapter.notifyDataSetChanged();
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
我的导航抽屉或适配器中没有代码在更新时被更改。
答案 0 :(得分:1)
我搜索了一下这个问题:
ListView
缓存元素计数,无论何时必须布置其子项,它都会再次检查绑定适配器中当前项目数的计数。如果计数已更改且ListView未通知此情况,则会引发错误:
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() + ")]");
}
我不确定是否在另一个线程上调用了onIabPurchaseFinished()
。但是,如果你真的不在其他地方做任何改变,我认为存在问题。
让我们说,它是在另一个线程上。因此,当您调用MyApp.didUpgrade = true;
时,适配器内容会被另一个线程更改,因为您在适配器内调用了if (MyApp.didUpgrade) {
。然后列表视图调用layoutChildren()
并具有旧数量的getcount()。我想这就是你得到这个错误的原因。
尝试在runOnUiThread()
MyApp.didUpgrade = true;
dAdapter.notifyDataSetChanged();
答案 1 :(得分:1)
我建议你查看你写给MyApp.didUpgrade
的其他任何地方
也许在mHelper.queryInventoryAsync(..)
的回调中?
我怀疑以下内容:
1.您致电mHelper.queryInventoryAsync
查看用户广告资源。该调用是异步的,因此线程将等待答案
2.活动及其抽屉内容被夸大,列表中包含13个项目
3. queryInventoryAsync
现在返回并触发您的回调,您设置MyApp.didUpgrade = true
但忘记拨打notifyDataSetChanged()
。
4.由于任何原因重绘了抽屉内容 - 抛出异常,因为count()
现在返回12并且android认为该列表已损坏。
您是否仅向已购买升级的用户收到错误报告? 另请注意,即使抽屉未打开,创建激活时抽屉中的视图也会膨胀。