片段视图上的 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()
不是一个可靠的方法来假设片段视图已经附加到视图树。
我在扩展 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()
不是一个可靠的方法来假设片段视图已经附加到视图树。