Android 什么时候认为 window 泄露了?

When does Android consider a window is leaked?

查看了Android源码,发现有如下方法。 (core/java/android/view/WindowManagerGlobal.java)

似乎 who != null 时 window/view 被泄露了。谁能解释这背后发生了什么?

public void closeAll(IBinder token, String who, String what) {
        synchronized (mLock) {
            int count = mViews.size();
            //Log.i("foo", "Closing all windows of " + token);
            for (int i = 0; i < count; i++) {
                //Log.i("foo", "@ " + i + " token " + mParams[i].token
                //        + " view " + mRoots[i].getView());
                if (token == null || mParams.get(i).token == token) {
                    ViewRootImpl root = mRoots.get(i);

                    //Log.i("foo", "Force closing " + root);
                    if (who != null) {
                        WindowLeaked leak = new WindowLeaked(
                                what + " " + who + " has leaked window "
                                + root.getView() + " that was originally added here");
                        leak.setStackTrace(root.getLocation().getStackTrace());
                        Log.e(TAG, "", leak);
                    }

                    removeViewLocked(i, false);
                }
            }
        }
    }

我检查了来源... 我不是很确定,但她是我的理解...

"who" 参数是 Activity 仅名称

查看closeAll()调用方法,可以看到who就是Activityclass被销毁留下一个window的名字:

WindowManagerGlobal.getInstance().closeAll(wtoken,
                        r.activity.getClass().getName(), "Activity");

如果发生泄漏则调用 closeAll()

似乎 WindowManagerGlobal.closeAll() 在 Windows 已经泄漏时被调用。所以,who != null 它只是检查以确保 String 不是 NULL

如果不为空,则创建 WindowLeaked 并打印日志。 WindowLeaked 是扩展 AndroidRuntimeException

的 Class
final class WindowLeaked extends AndroidRuntimeException {
    public WindowLeaked(String msg) {
        super(msg);
    }
}

最重要的是,如果调用 WindowManagerGlobal.closeAll(),则意味着 Windows 已经泄漏。

CloseAll()调用方法

View.java中,我们可以看到当检测到泄漏时调用了WindowManagerGlobal.closeAll()

ActivityThread.java

private void handleDestroyActivity(IBinder token, boolean finishing,
                                    int configChanges, boolean getNonConfigInstance) {
    ...
    IBinder wtoken = v.getWindowToken();
    ...
    if (wtoken != null && r.mPendingRemoveWindow == null) {
        WindowManagerGlobal.getInstance().closeAll(wtoken,
                r.activity.getClass().getName(), "Activity");
    }

在上面的代码中,我们可以看到当发现不一致时会触发 WindowManagerGlobal.closeAll()

  1. wtoken != null wtoken 表示 View 有一个 mAttachInfo.mWindowToken 信息。换句话说,它仍然被一些 window.
  2. 持有
  3. r.mPendingRemoveWindow == null 没有待删除的视图。

所以,这是不一致的。附加了一个视图(还有 mAttachInfo)但我已经删除了所有未决的 windows(mPendingRemoveWindow 为空)...因此,该视图已泄漏。

希望能帮到你 此致

REF:

WindowManagerGlobal

ActivityThread

View