正确使用WindowManager.removeViewImmediate()

时间:2018-10-09 18:00:49

标签: android android-windowmanager

WindowManager.removeViewImmediate()的文档包含警告(强调我的意思):

  

ViewManager.removeView(View)的特殊变体,在返回之前立即调用给定视图层次结构的View.onDetachedFromWindow()方法。 这不适用于普通应用;正确使用它需要格外小心。

我很好奇“精心护理”在这里的含义。大概这表明除非我知道如何处理使用它的所有副作用,否则我不应该调用此方法……但是我什至不知道这些副作用可能是什么。


请考虑以下活动,我已尽可能将其制成。没有遗漏的代码(除了导入),并且Activity的主题只是一个普通的AppCompat主题:

public class MainActivity extends AppCompatActivity {

    private View overlay;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getWindow().getDecorView().post(() -> {
            overlay = new View(this);
            overlay.setBackgroundColor(Color.RED);

            WindowManager.LayoutParams params =
                    new WindowManager.LayoutParams(WindowManager.LayoutParams.FLAG_FULLSCREEN);

            getWindowManager().addView(overlay, params);
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getWindowManager().removeView(overlay);
    }
}

当我运行我的应用程序并将设备从纵向旋转到横向(或导致其被破坏并重新创建的任何其他方式)时,这将出现在日志栏中:

2018-10-09 13:58:02.162 11270-11270/com.example.stackoverflow E/WindowManager: android.view.WindowLeaked: Activity com.example.stackoverflow.MainActivity has leaked window android.view.View{e99861 V.ED..... ........ 0,0-1080,1920} that was originally added here
        at android.view.ViewRootImpl.<init>(ViewRootImpl.java:511)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:346)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
        at com.example.stackoverflow.MainActivity.lambda$onCreate$0(MainActivity.java:25)

但是,如果我将onDestroy()方法更改为使用removeViewImmedate(),则此错误将永远不会出现在日志中。不过,我很犹豫,因为我不知道切换这些呼叫还会影响什么。仅仅说“有效”不足以让我放心。

1 个答案:

答案 0 :(得分:0)

WinowManager由WindowManagerImpl实现。

WindowManagerImpl#removeViewImmediate(View)WindowManagerImpl#removeView(View)都呼叫WindowManagerGlobal#removeView(View, boolean)

区别在于removeViewImmediate()true传递给该布尔参数,该变量告诉WindowManagerGlobal该View应该立即删除而不是等待。

虽然这可能很不言自明。

我唯一想到的可能是立即删除一个问题是奇怪的绘图错误。在对源方法的评论中说:

  

/ **        * @param Instant True,请立即进行遍历。错误,请排队,然后再做。        * @return True,请求已排队。错误,请求已完成。        * /

这没有多大意义。

老实说,如果它不会导致崩溃,而是删除该泄漏警告,则最好使用它。

WindowManagerGlobal#removeViewLocked(View, boolean)

ViewRootImpl#die(boolean)