片段视图上的 getParent() returns 旋转后 onResume() 中的 null

getParent() on Fragment View returns null in onResume() after rotation

我在扩展 ListFragment 的自定义片段中的 onResume() 中有以下代码,它试图找到它的父级:

@Override
public void onResume() {
    super.onResume();

    System.out.println("resume");
    View view = getView();
    System.out.println("view is " + (view != null ? "not " : "" ) + "null");
    ViewParent parent = view != null ? view.getParent() : null;
    System.out.println("parent is " + (parent != null ? "not " : "" ) + "null");
    if(view != null) {
        System.out.println(view.getRootView());
    }
}

当我 运行 应用程序最初在模拟器中打印时:

I/System.out: resume
I/System.out: view is not null
I/System.out: parent is not null
I/System.out: com.android.internal.policy.impl.PhoneWindow$DecorView{ ... }

但是,在旋转模拟器后,它会打印:

I/System.out: resume
I/System.out: view is not null
I/System.out: parent is null
I/System.out: android.widget.FrameLayout{ ... }

即使片段在应用程序中可见得很好,但在旋转后 onResume() 中,它的视图似乎没有正确附加到视图树中,因为根视图是 FrameLayout 这是片段的根视图,而不是应用程序的根视图。

这可能是什么原因造成的,我怎样才能正确访问它的 ViewParent in/after onResume(),而不求助于行 getActivity().findViewById(someId)?


编辑:

当我调整 onResume() 中的代码以在下一帧打印根视图(使用 View.post())时,它 找到了正确的根查看(这意味着我可以访问父级):

@Override
public void onResume() {
    super.onResume();

    System.out.println("resume");
    View view = getView();
    System.out.println("view is " + (view != null ? "not " : "" ) + "null");
    ViewParent parent = view != null ? view.getParent() : null;
    System.out.println("parent is " + (parent != null ? "not " : "" ) + "null");
    if(view != null) {
        System.out.println(view.getRootView());
        
        /**
         * added to see if it finds the proper root view in the next frame 
         */
        view.post(() -> {
            System.out.println("how about after post?");
            System.out.println(view.getRootView());
        });
    }
}

现在打印:

I/System.out: view is not null
I/System.out: parent is null
I/System.out: android.widget.FrameLayout{ ... }
I/System.out: how about after post?
I/System.out: com.android.internal.policy.impl.PhoneWindow$DecorView{ ... }

但是像这样使用 View.post() 感觉就像是一个讨厌的黑客。


编辑:

所以,操作顺序似乎与我预期的不同(可能是错误?)。

但我可能找到了解决方案,如果它按预期工作,我将 post 作为答案。这个想法是在 onViewCreated() 中的片段视图中添加一个 View.OnAttachStateChangeListener ,从而在 View.OnAttachStateChangeListener.onViewAttachedToWindow() 而不是 Fragment.onResume().

中找到父级

我已经通过将我的逻辑从 onResume() 移动到我在 onViewCreated() 中添加的 View.OnAttachStateChangeListener 来解决问题:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
        @Override
        public void onViewAttachedToWindow(View view) {
            System.out.println(view.getParent());
        }

        @Override
        public void onViewDetachedFromWindow(View view) {
            view.removeOnAttachStateChangeListener(this);
        }
    };
}

现在它的行为符合我的预期。

take-away 是 onResume() 不是一个可靠的方法来假设片段视图已经附加到视图树。