9

ListActivity在使用用户选择的项目的内容打开一个新活动后返回原始状态时出现此异常。它只发生在冰淇淋三明治上。

这是跟踪:

 java.lang.IllegalArgumentException: The observer is null.
    at android.database.Observable.unregisterObserver(Observable.java:59)
    at android.widget.BaseAdapter.unregisterDataSetObserver(BaseAdapter.java:42)
    at android.widget.AbsListView.onDetachedFromWindow(AbsListView.java:2373)
    at android.view.View.dispatchDetachedFromWindow(View.java:9756)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2274)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2272)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2272)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2272)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2272)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2272)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2272)
    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2272)
    at android.view.ViewRootImpl.dispatchDetachedFromWindow(ViewRootImpl.java:2227)
    at android.view.ViewRootImpl.doDie(ViewRootImpl.java:3679)
    at android.view.ViewRootImpl.die(ViewRootImpl.java:3667)
    at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:320)
    at android.view.WindowManagerImpl$CompatModeWrapper.removeViewImmediate(WindowManagerImpl.java:139)
    at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3144)
    at android.app.ActivityThread.access$1200(ActivityThread.java:122)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1179)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4340)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    at dalvik.system.NativeStart.main(Native Method)

堆栈中没有提到我的代码,所以这真的让我很困惑,我不能做一个肮脏的捕获:/

DataSetObserver我仅在创建活动时才注册匿名。该活动还嵌入在 ActivityGroup 中(在 4.0 中已弃用但仍应支持它,我希望如此)。

有人对新操作系统有这个问题吗?

提前致谢。


更新:

好的,我想我找到了问题的根源,虽然不知道如何解决它。

里面AbsListView.onDetachedFromWindow()我们有这个:

if (mAdapter != null) { // Android code added on ICS
    mAdapter.unregisterDataSetObserver(mDataSetObserver);
    mDataSetObserver = null;
}

哪个,一旦观察者被取消注册,它就会被取消。问题来了,由于某种原因,在 ICS 中它被调用了两次。我认为像在类中那样检查删除操作中的空参数有点愚蠢Observable

public void unregisterObserver(T observer) { // Android code
    if (observer == null) {
        throw new IllegalArgumentException("The observer is null.");
    }
    synchronized(mObservers) {
        int index = mObservers.indexOf(observer);
        if (index == -1) {
            throw new IllegalStateException("Observer " + observer + " was not registered.");
        }
        mObservers.remove(index);
    }
}

他们为什么不直接忽略它 ¬¬ 他们可以这样做并且也能正常工作(或更好):

public void unregisterObserver(T observer) { // Android code
    synchronized(mObservers) {
        mObservers.remove(observer);
    }
}
4

2 回答 2

11

这个问题是在Android 4.0.3 中引入的,并且Observable 类被更改为在多次释放观察者时抛出异常。它已被报告为错误,可以在此处阅读:http ://code.google.com/p/android/issues/detail?id=22946 。

解决此问题的最简单方法是封装底层适配器并避免多次发布。

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
  if (observer != null) {
    super.unregisterDataSetObserver(observer);
  }
} 

但这并不适用于所有情况,例如 ExpandableListView 有一个无法访问的内部适配器。这里的另一种解决方案是包装 ExpandableListView 并捕获异常。这个解决方案对我有用,我还没有发现任何副作用。

public class PatchedExpandableListView extends ExpandableListView {

  public PatchedExpandableListView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override
  protected void onDetachedFromWindow() {
    try {
      super.onDetachedFromWindow();
    } catch(IllegalArgumentException iae) {
      // Workaround for http://code.google.com/p/android/issues/detail?id=22751
    }
  }
}
于 2012-02-07T09:34:12.973 回答
3

我犯了一个愚蠢的错误,认为跟踪中没有提到我的任何类,但 LoadingDataView 就是其中之一。它没有显示在原始跟踪中,而是显示在另一个相关的跟踪中。

在那个类里面有一个匿名的 ArrayAdapter 是事件发生的地方,所以我添加了这个作为解决方法:

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
    if (observer != null) {
        super.unregisterDataSetObserver(observer);
    }
}

它现在似乎可以工作了,虽然我仍然不确定为什么这个方法被调用了两次。

虽然,现在我将尽可能多地使用 Fragments ;)

于 2011-12-15T10:58:31.440 回答