调用ViewGroup#addView和ViewGroup #removeView会导致NullPointerException

时间:2014-02-18 19:58:28

标签: android android-view android-framelayout

在方法中,我按如下方式调用addViewremoveView

public class EnclosingClass extends FrameLayout {
    ...
    void fooMethod() {
        ...
        viewGroup1.addView(this);
        viewGroup2.removeView(this);
        ...
    }
    ...
}

这在肖像模式下工作正常(它被多次调用没有任何问题),但只要我将屏幕方向更改为横向,我就会得到NullPointerException :(仅供参考,{{1}在方向更改期间从surfaceChanged调用}:

fooMethod

为了解决这个问题,我将 18376 AndroidRuntime E FATAL EXCEPTION: main 18376 AndroidRuntime E Process: com.google.android.apps.chrome, PID: 18376 18376 AndroidRuntime E java.lang.NullPointerException 18376 AndroidRuntime E at android.widget.FrameLayout.layoutChildren(FrameLayout.java:405) 18376 AndroidRuntime E at android.widget.FrameLayout.onLayout(FrameLayout.java:388) 18376 AndroidRuntime E at android.view.View.layout(View.java:14817) 18376 AndroidRuntime E at android.view.ViewGroup.layout(ViewGroup.java:4631) 18376 AndroidRuntime E at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453) 18376 AndroidRuntime E at android.widget.FrameLayout.onLayout(FrameLayout.java:388) 18376 AndroidRuntime E at android.view.View.layout(View.java:14817) 18376 AndroidRuntime E at android.view.ViewGroup.layout(ViewGroup.java:4631) 18376 AndroidRuntime E at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453) 18376 AndroidRuntime E at android.widget.FrameLayout.onLayout(FrameLayout.java:388) 18376 AndroidRuntime E at android.view.View.layout(View.java:14817) 18376 AndroidRuntime E at android.view.ViewGroup.layout(ViewGroup.java:4631) 18376 AndroidRuntime E at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1987) 18376 AndroidRuntime E at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1744) 18376 AndroidRuntime E at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000) 18376 AndroidRuntime E at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670) 18376 AndroidRuntime E at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761) 18376 AndroidRuntime E at android.view.Choreographer.doCallbacks(Choreographer.java:574) 18376 AndroidRuntime E at android.view.Choreographer.doFrame(Choreographer.java:544) 18376 AndroidRuntime E at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747) 18376 AndroidRuntime E at android.os.Handler.handleCallback(Handler.java:733) 18376 AndroidRuntime E at android.os.Handler.dispatchMessage(Handler.java:95) 18376 AndroidRuntime E at android.os.Looper.loop(Looper.java:136) 18376 AndroidRuntime E at android.app.ActivityThread.main(ActivityThread.java:5017) 18376 AndroidRuntime E at java.lang.reflect.Method.invokeNative(Native Method) 18376 AndroidRuntime E at java.lang.reflect.Method.invoke(Method.java:515) 18376 AndroidRuntime E at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 18376 AndroidRuntime E at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 18376 AndroidRuntime E at dalvik.system.NativeStart.main(Native Method) addView放在removeView内,如下所示:

Runnable

这确实解决了问题,而且一切似乎都运转良好,但我不明白为什么。如何将方法放入消息队列中有助于解决问题?另外,为什么我在堆栈跟踪中看不到对代码的任何引用?我通过逐渐注释掉代码来找到问题。

1 个答案:

答案 0 :(得分:0)

public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }`enter code here`
}

因为你真的在UIThread上使用runOnUiThread,所以代码运行在else分支:action.run()这是一个串行操作。如果其他api仍在UI线程上运行本地mChildCount,则会遇到NULL指针,(UI线程不安全)