Correct usage of WindowManager.removeViewImmediate()
Asked Answered
M

1

6

The documentation for WindowManager.removeViewImmediate() contains a warning (emphasis mine):

Special variation of ViewManager.removeView(View) that immediately invokes the given view hierarchy's View.onDetachedFromWindow() methods before returning. This is not for normal applications; using it correctly requires great care.

I'm curious what exactly "great care" means here. Presumably this is an indication that I shouldn't be calling this method unless I know how to handle all of the side-effects of using it... but I don't even know what those side-effects might be.


Consider the following Activity, which I've made as vanilla as possible. There's no omitted code (other than imports), and the Activity's theme is just a vanilla AppCompat theme:

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);
    }
}

When I run my app, and rotate my device from portrait to landscape (or anything else that causes it to be destroyed and recreated), this appears in the logcat:

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)

However, if I change my onDestroy() method to use removeViewImmedate() instead, then this error never appears in my logs. I'm hesitant to do this, though, because I don't know what else could be affected by switching these calls. Just saying "it works" isn't enough to put my mind at ease.

Mo answered 9/10, 2018 at 18:0 Comment(0)
N
0

WinowManager is implemented by WindowManagerImpl.

WindowManagerImpl#removeViewImmediate(View) and WindowManagerImpl#removeView(View) both call WindowManagerGlobal#removeView(View, boolean).

The difference is that removeViewImmediate() passes true to that boolean argument, which tells WindowManagerGlobal that that View should be removed immediately instead of waiting.

That's probably pretty self-explanatory though.

The only thing I can think of that might make an immediate removal an issue is weird drawing errors. While the comments on the source methods say the following:

/** * @param immediate True, do now if not in traversal. False, put on queue and do later. * @return True, request has been queued. False, request has been completed. */

It doesn't make much sense.

Honestly, if it doesn't cause crashes, and instead removes that leak warning, you might as well use it.

WindowManagerGlobal#removeViewLocked(View, boolean)

ViewRootImpl#die(boolean)

Nymphomania answered 9/10, 2018 at 18:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.