Compose an image “off screen” on Android

Lisa Watkins
Code With Lisa
Published in
2 min readSep 27, 2018

There’s a variety of different reasons you’d like to compose an image “behind the scenes” — and its actually quite simple.

I’ve built a custom view that has a base image and some text layered over it. The image is not stored on the user’s device, but rather on a server somewhere. I’d like the user to be able to click a button and share or save the final composition created by my custom view. The trick here is I would like to do this without visibly drawing my custom view on the screen.

What makes this tricky? Well, first, I don’t want to just fetch the image. I need to do some stuff with it (i.e. layer some text over it) before I’m ready for the user to share or save it. Also, I don’t have access to the image locally.

I’ve created a custom view with a few convenience methods to handle fetching the image from the server and then add some text over the image. I’m not going to go into much further detail on my composition for the sake of simplicity. I’ve named my composition class MySecretCompositionView and extended FrameLayout.

First, create an empty layout file that will house your final composition. This is where I include my custom view. Set the height and width to the height and width (in pixels) of the image. Make sure this view is invisible (not gone).

In order for the Android OS to draw your composition, it needs to be attached to the window.

private void attachToWindow() {
WindowManager.LayoutParams layoutParams =
new WindowManager.LayoutParams();
windowManager = ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE));
windowManager.addView(mySecretCompositionView, layoutParams);
}

I have some code that fetches the image, adds the image as a background to my custom view, and adds the text “Code with Lisa” to a bottom corner of the image. I have a callback waiting for my image to load from the server. In my callback, I include the following code.

layoutObserver.addOnGlobalLayoutListener(new LayoutListener());

Now I am listening for any updates the Android OS makes to my view (i.e. I am listening for Android to set my custom view’s background to the fetched image).

LayoutListener will be called when the final composition has been drawn. Once it’s been called, we want to make sure to remove the callback so that we are not repeatedly called unintentionally when any future state within the layout changes.

Now I am ready to save my view as a bitmap and kick off a task to save this image to the user’s gallery. The code from LayoutListener is below.

Bitmap bitmap = mySecretCompositionView.getDrawingCache();SaveImageToGalleryTask saveImage = new saveImageToGalleryAsyncTask(bitmap);saveImage.execute();mySecretCompositionView
.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);

Hold on though, that’s not all! We have some clean up to do.

private void detachFromWindow() {
try {
windowManager.removeView(mySecretCompositionView);
} catch (IllegalArgumentException e) {
Log.d(PhotoManager.getSimpleClassName(), "View not attached to window manager");
}
}

Since we’re done with our composition, we need to make sure to remove our custom view from the WindowManager to avoid unintended consequences as the user continues to enjoy our app.

Happy coding!

--

--

Lisa Watkins
Code With Lisa

Engineer, Activist, Cat Lady. Mobile engineering @ Lyft.