view.getViewTreeObserver().addOnGlobalLayoutListener 泄漏片段
view.getViewTreeObserver().addOnGlobalLayoutListener leaks Fragment
当我使用 GlobalLayoutListener
查看 softKeyboard 是否打开时,片段在被销毁后不再是 garbageCollected。
我的工作:
- 我删除了 Fragment
的 onDestroy()
中的监听器
- 我在
onDestroy()
中将监听器设置为 null
- 我在
onDestroy()
中将观察到的视图设置为null
还在泄露片段
有没有人遇到过类似的问题并且知道解决方法??
我的onDestroy
:
@Override
public void onDestroy(){
Log.d(TAG , "onDestroy");
if(Build.VERSION.SDK_INT < 16){
view.getViewTreeObserver().removeGlobalOnLayoutListener(gLayoutListener);
}else{
view.getViewTreeObserver().removeOnGlobalLayoutListener(gLayoutListener);
}
view = null;
gLayoutListener = null;
super.onDestroy();
}
您可以尝试创建自定义布局并将其作为根视图放置在 xml 中,而不是使用它。
class CustomLayout extends LinearLayout{
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
然后重写onsizechanged方法
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (h < oldh) {
// there is a difference, means keyboard is open.
} else {
}
}
我假设您的应用程序只支持一种模式(纵向或横向)
更新:
尽
@Override
public void onDestroyView(){
super.onDestroyView();
}
因为我认为您正在 onCreateView()
中初始化侦听器,所以应在 onDestoryView()
中删除侦听器。 onDestroy() 只会在片段被销毁时调用,不会在状态更改期间调用。
我遇到了同样的问题,但我通过删除 onDestroy() 中的侦听器解决了这个问题。注意 JellyBean 周围的使用方法发生了变化。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
}
@Override
public void onDestroy() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
mView.getViewTreeObserver().removeGlobalOnLayoutListener(mGlobalLayoutListener);
} else {
mView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
}
super.onDestroy();
}
好吧,也许这有点矫枉过正,但没有消息来源很难确定,所以试试这个。使您的 gLayoutListener
成为静态内部 class(不要保留对您的片段的强引用)。
如果您需要对片段或其侦听器中的字段执行某些操作,请在自定义侦听器 class 的构造函数中创建一个 WeakReference<YourFragment>
并通过此引用访问您的片段。不要忘记检查 weakref.get() != null
.
我强烈认为在 onDestroy
() 中删除 View 对象引用的 Listener 为时已晚。此覆盖方法发生在 onDestroyView
() 之后,它应该“...清理与其视图关联的资源”。
您可以在 onStop()
中使用相同的代码。虽然我没有用到这个技巧
我可以推荐这段代码,我在调试器中使用它没有任何问题。
// Code below is an example. Please change it to code that is more applicable to your app.
final View myView = rootView.findViewById(R.id.myView);
myView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@SuppressLint("NewApi") @SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
// Obtain layout data from view...
int w = myView.getWidth();
int h = myView.getHeight();
// ...etc.
// Once data has been obtained, this listener is no longer needed, so remove it...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
myView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
else {
myView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
备注:
- 由于
getViewTreeObserver
用于布局,通常您只需要很短的时间使用此侦听器。因此侦听器会立即被删除。
- 第二次调用
removeOnGlobalLayoutListener
() 应该被 Studio 划掉,因为它在 JELLY_BEAN 之前不可用。
- 如果您使用 Android Studio,则不需要 Pragma 代码
@SuppressWarnings("deprecation")
。
- 代码
myView = rootView.findViewById(R.id.myView);
可能需要更改为更适用于您的应用或情况的代码。
我在自定义视图中也遇到了这个问题。我在自定义视图构造函数中的子视图上注册了 onPreDrawListener
,并在 onDetachedFromWindow
中注销了它。内存泄漏仍然存在。为了解决这个问题,我尝试了一切,但最后我不得不编写一个不基于 TreeObserver 的替代机制。
当我使用 GlobalLayoutListener
查看 softKeyboard 是否打开时,片段在被销毁后不再是 garbageCollected。
我的工作:
- 我删除了 Fragment 的
- 我在
onDestroy()
中将监听器设置为 - 我在
onDestroy()
中将观察到的视图设置为null
onDestroy()
中的监听器
null
还在泄露片段
有没有人遇到过类似的问题并且知道解决方法??
我的onDestroy
:
@Override
public void onDestroy(){
Log.d(TAG , "onDestroy");
if(Build.VERSION.SDK_INT < 16){
view.getViewTreeObserver().removeGlobalOnLayoutListener(gLayoutListener);
}else{
view.getViewTreeObserver().removeOnGlobalLayoutListener(gLayoutListener);
}
view = null;
gLayoutListener = null;
super.onDestroy();
}
您可以尝试创建自定义布局并将其作为根视图放置在 xml 中,而不是使用它。
class CustomLayout extends LinearLayout{
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
然后重写onsizechanged方法
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (h < oldh) {
// there is a difference, means keyboard is open.
} else {
}
}
我假设您的应用程序只支持一种模式(纵向或横向)
更新:
尽
@Override
public void onDestroyView(){
super.onDestroyView();
}
因为我认为您正在 onCreateView()
中初始化侦听器,所以应在 onDestoryView()
中删除侦听器。 onDestroy() 只会在片段被销毁时调用,不会在状态更改期间调用。
我遇到了同样的问题,但我通过删除 onDestroy() 中的侦听器解决了这个问题。注意 JellyBean 周围的使用方法发生了变化。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
}
@Override
public void onDestroy() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
mView.getViewTreeObserver().removeGlobalOnLayoutListener(mGlobalLayoutListener);
} else {
mView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
}
super.onDestroy();
}
好吧,也许这有点矫枉过正,但没有消息来源很难确定,所以试试这个。使您的 gLayoutListener
成为静态内部 class(不要保留对您的片段的强引用)。
如果您需要对片段或其侦听器中的字段执行某些操作,请在自定义侦听器 class 的构造函数中创建一个 WeakReference<YourFragment>
并通过此引用访问您的片段。不要忘记检查 weakref.get() != null
.
我强烈认为在 onDestroy
() 中删除 View 对象引用的 Listener 为时已晚。此覆盖方法发生在 onDestroyView
() 之后,它应该“...清理与其视图关联的资源”。
您可以在 onStop()
中使用相同的代码。虽然我没有用到这个技巧
我可以推荐这段代码,我在调试器中使用它没有任何问题。
// Code below is an example. Please change it to code that is more applicable to your app.
final View myView = rootView.findViewById(R.id.myView);
myView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@SuppressLint("NewApi") @SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
// Obtain layout data from view...
int w = myView.getWidth();
int h = myView.getHeight();
// ...etc.
// Once data has been obtained, this listener is no longer needed, so remove it...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
myView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
else {
myView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
备注:
- 由于
getViewTreeObserver
用于布局,通常您只需要很短的时间使用此侦听器。因此侦听器会立即被删除。 - 第二次调用
removeOnGlobalLayoutListener
() 应该被 Studio 划掉,因为它在 JELLY_BEAN 之前不可用。 - 如果您使用 Android Studio,则不需要 Pragma 代码
@SuppressWarnings("deprecation")
。 - 代码
myView = rootView.findViewById(R.id.myView);
可能需要更改为更适用于您的应用或情况的代码。
我在自定义视图中也遇到了这个问题。我在自定义视图构造函数中的子视图上注册了 onPreDrawListener
,并在 onDetachedFromWindow
中注销了它。内存泄漏仍然存在。为了解决这个问题,我尝试了一切,但最后我不得不编写一个不基于 TreeObserver 的替代机制。