Skip to content Skip to sidebar Skip to footer

Call Release() Did Not Work After Creating Virtual Display

I used MediaProjection to create VirtualDisplay to take screenshots. Afterward, I tried to release the virtualDisplay, but it did not work: // create virtual display... mVirtualDis

Solution 1:

1 line answer : virtualdisplay.release() do nothing if you create the virtualdisplay passing a null as the parameter for the callback.

I find this is a very frustating problem because all of the samples I came across on the web pass NULL for the callback parameter and yet in all of the samples, call release() without realizing it does absolutely nothing due to unclear android documentation thus the memory leak. Though I do have to mention I didn't find this problem in older Android versions

Found the answer from VirtualDisplay source code. When you are creating a VirtualDisplay, you NEED to make a VirtualDisplay.Callback and pass is as a parameter, not a NULL. because virtualDisplay.release() function checks if the token is null or not.

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/hardware/display/VirtualDisplay.java

VirtualDisplay.java

   /**
 * Releases the virtual display and destroys its underlying surface.
 * <p>
 * All remaining windows on the virtual display will be forcibly removed
 * as part of releasing the virtual display.
 * </p>
 */publicvoidrelease() {
    if (mToken != null) { //mToken is the callback
        mGlobal.releaseVirtualDisplay(mToken);
        mToken = null;
    }
}

So before you call createVirtualDisplay, make a VirtualDisplay.Callback

VirtualDisplay.Callback mVirtualDisplayCallback = newVirtualDisplay.Callback() {
        @OverridepublicvoidonPaused() {
            super.onPaused();
        }

        @OverridepublicvoidonResumed() {
            super.onResumed();
        }

        @OverridepublicvoidonStopped() {
            super.onStopped();
        }
    };
    mVirtualDisplay = mProjection.createVirtualDisplay("screen-mirror", mWidth, mHeight, mDensity, flags, mImageReader.getSurface(), mVirtualDisplayCallback, handler);

if you go see the VirtualDisplay class, you will find this variable and constructor

VirtualDisplay.java

private IVirtualDisplayCallback mToken;

VirtualDisplay(DisplayManagerGlobal global, Display display,
        IVirtualDisplayCallback token, Surface surface) {
    mGlobal = global;
    mDisplay = display;
    mToken = token;
    mSurface = surface;
}

the mToken / VirtualDisplay callback on the constructor is that token that the release() function checks on whether it is null or not before calling

   mGlobal.releaseVirtualDisplay(mToken);

This is very frustating on because release() function documentation doesn't mention this at all.

So to check whether this solution works, check the number of displays and the ids before releasing the virtual display and check again after releasing it. The supposed display id should be released.

DisplayManagerdisp= (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
    Display[] allDisplays = disp.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
    Log.e(TAG ,  text);
    Log.e(TAG , "Display Count  " + allDisplays.length);
    for (Display dl : allDisplays) {
        Log.e(TAG , "Display name: " + dl.getName() + " Display id: " + dl.getDisplayId());
    }

enter image description here

Post a Comment for "Call Release() Did Not Work After Creating Virtual Display"