view.getViewTreeObserver().addOnGlobalLayoutListener 泄漏片段

view.getViewTreeObserver().addOnGlobalLayoutListener leaks Fragment

当我使用 GlobalLayoutListener 查看 softKeyboard 是否打开时,片段在被销毁后不再是 garbageCollected。

我的工作:

还在泄露片段

有没有人遇到过类似的问题并且知道解决方法??

我的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() 只会在片段被销毁时调用,不会在状态更改期间调用。

勾选Fragment life cycle

我遇到了同样的问题,但我通过删除 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 的替代机制。