Activity Embedding in Android
codeblogs
Google released Android 12L to improve the Android feel and experience on foldables, tablets, Chrome OS devices and in general, large screens. This release comes at a time when large screens are growing in reach, thus increasing the need to scale app UI to support a wide range of screen sizes.
Android 12L introduced many improvements, from multitasking and split-screen features to UI optimization and polishing. It was also accompanied by developer tools and APIs to make building, designing and testing on large screens easier.
This post goes over Activity
embedding, an addition to Android 12L that brings support for multi-pane layouts in Activity
based apps. The post goes over how Activity
embedding impacts app behavior on both small and large screens, how to add support for it in your app, and how to configure it and control aspects such as Activity
launch and back navigation.
The code samples used in this post can be found here.
Introducing Activity
Embedding
Activity
embedding was recently introduced in Jetpack WindowManager. It’s available for large screen devices with Android 12L. It brings support for multi-pane layouts to Activity
based apps, allowing developers to provide an improved user experience on large screens without significant refactoring/migration to Fragments
or Jetpack Compose.
Activity
embedding splits the task window into 2 containers, a primary container and a secondary one. On large screens, primary and secondary Activities
are laid out side by side, whereas on small screens, secondary activities are stacked on top of primary ones. The system handles this behavior depending on the configuration the app defines.
Left: Primary and secondary Activities side by side on a large screen. Right: Secondary Activities stacked on top of primary Activities on a small screen.
Use Case: List/Details Pattern
The list/details pattern is commonly used in apps. On small screens, the list and details screens are each shown on their own. On large screens though, showing the list and details screens side by side can make better use of the available real estate on the screen and provide a better user experience.
Let’s assume we have an app where the list and details screens are defined in ListActivity
and DetailsActivity
respectively. This is how they would look on small and large screens.
Left: List/Details screens in a large screen. Right: List/Details screens in a small screen.
List/Details with Activity Embedding
Adding support for Activity
embedding in this app can be achieved in 3 simple steps.
- Add the
WindowManager
dependency to the app’sbuild.gradle
file.Activity
embedding was introduced in[version 1.0.0-beta03](https://developer.android.com/jetpack/androidx/releases/window#1.0.0-beta03)
, so make sure to use a version as recent as this one at minimum.
2. Create a configuration file in the folder res/xml
. In it, you’ll provide rules to define how and which Activities
should be split. The system will later use them to decide how to handle embedding them. The following is the minimum required configuration.
3. Initialize [SplitController](https://developer.android.com/reference/androidx/window/embedding/SplitController)
. This has to be done before the app loads and starts its Activities
. One option is to perform this initialization on app launch inside the Application
class, another is to use the Jetpack Startup library.
ListActivity
and DetailsActivity
will now be displayed side by side on large screens. On small screens though, the app will continue to behave the same, that is, when DetailsActivity
is launched, it is stacked on top of ListActivity
.
Left: List/Details screens side by side in a large screen. Right: List/Details screens stacked in a small screen.
Adding a Placeholder
Activity
embedding provides a way to display a placeholder Activity
in the secondary container until there’s content to show in it. This is useful in the list/details use case for when the user hasn’t selected an item from the list yet.
The placeholder Activity
is only shown when there is enough space for a split. It stays displayed until there is content to show, in which case it is dismissed.
Setting a placeholder Activity
DetailsPlaceholderActivity
as a placeholder until a list item is selected is quite simple. Just define a rule for it in the split configuration file.
This results in a placeholder Activity
being displayed initially on large screens before an item from the list has been selected.
The list and placeholder screens side by side
Back Navigation
When navigating back using gesture navigation or the back button, the back event is sent to the focused Activity
, that is the Activity
that was last touched or last launched. The system then finishes it. By default, finishing all Activities
in one container results in the other container filling the entire space of the screen.
Finishing the secondary container’s Activities results in the primary container expanding to fill the whole screen.
Finishing the primary container’s Activities results in the secondary container expanding to fill the whole screen.
Activity
embedding provides 2 options to control how Activities
in the primary and secondary container are finished.
finishPrimaryWithSecondary
: When set to true
, the system finishes the Activity
in the primary container when all Activities
in the secondary container are finished. By default it’s set to false
.
finishSecondaryWithPrimary
: When set to true
, the system finishes Activities
in the secondary container when all Activities
in the primary container are finished. By default it’s set to true
.
Going back to our example, we’d like ListActivity
to finish when DetailsActivity
finishes, and vice versa, DetailsActivity
should finish when ListActivity
finishes. This is achieved using the following configuration.
Testing this code on a large screen doesn’t result in the expected behavior though. This might be due to a bug in the library.
Multiple Activities
DetailsActivity
is displayed in the secondary container. If it were to launch another Activity
, ShareActivity
, the latter would be stacked at the top of this container.
ShareActivity stacked on top of DetailsActivity when it is launched
Besides this default launch behavior, Activity
embedding provides the option to shift splits sideways when launching an Activity
from the secondary container. That means that DetailsActivity
would move to the primary container, and ShareActivity
would be launched in the secondary container.
DetailsActivity launches ShareActivity to the side and shifts the split
To support this behavior, you need to define the corresponding split rule for DetailsActivity
and ShareActivity
.
The above configuration specifies that DetailsActivity
should launch in the secondary container when it’s started by ListActivity
, and should display in the primary container when it launches ShareActivity
. The system handles animating DetailsActivity
as it moves between containers.
Split shift in action
Split Rule Configuration Options
Activity
embedding provides a couple of options to configure split rules:
splitRatio
: A float that defines the ratio of the primary container to the secondary container. By default it’s set to 0.5, meaning that each container occupies half the available screen width. It appears that this parameter is mandatory, failing to set it results in splits not working.
splitMinWidth
: A dimension that defines the minimum window width to trigger a split. If the window width is smaller than this value, Activities
in the secondary container will be stacked on top of Activities
in the primary one. By default, it’s set to 600dp
.
splitMinSmallestWidth
: Similar to splitMinWidth
, except that it takes into account both the window’s width and height.
clearTop
: A boolean that defines whether to clear all Activities
in the secondary container when launching an Activity
in a split with the same primary container. By default, it’s set to false
.
Listening to Split Events
Activity
embedding provides an API to receive notifications about split changes, allowing the app to react to them.
A split listener is registered using [SplitController.addSplitListener()](https://developer.android.com/reference/androidx/window/embedding/SplitController#addSplitListener%28android.app.Activity,java.util.concurrent.Executor,androidx.core.util.Consumer%29)
. This method takes an Activity
as an argument, which ensures the listener only receives updates about active splits the Activity
is part of. It also accepts an [Executor](https://developer.android.com/reference/java/util/concurrent/Executor.html)
on which updates are received.
A split listener should be unregistered using [SplitController.removeSplitListener()](https://developer.android.com/reference/androidx/window/embedding/SplitController#removeSplitListener%28androidx.core.util.Consumer%29)
.
This split listener is a [Consumer](https://developer.android.com/reference/androidx/core/util/Consumer)
that receives a list of [SplitInfo](https://developer.android.com/reference/androidx/window/embedding/SplitInfo)
on each update, each including information about Activities
in the primary and secondary containers, as well as the split ratio.
A common scenario for using a split listener is to update the UI. An example is showing or hiding a [FloatingActionButton](https://developer.android.com/reference/com/google/android/material/floatingactionbutton/FloatingActionButton)
(FAB) depending on the state of the split. Using our list/details app, imagine the FAB is part of ListActivity
. On a large screen where ListActivity
and DetailsActivity
are displayed side by side, ListActivity
should hide the FAB, whereas DetailsActivity
should show it. On small screens though, ListActivity
should be the one to show the FAB.
You can find the code for this example here in the code sample.
Using a split listener to show a FAB in DetailsActivity on the initial screen, and hide it when it launches ShareActivity.
Split Support
Activity
embedding is supported on large screen devices running API levels 32 or higher. Some devices with earlier versions may support it though, this depends on the OEM and whether they retroactively add support for it.
When running on Android 12L, large screen emulators and the resizable emulator included in Android Studio Chipmunk also support Activity
embedding.
You can check if a device supports Activity
embedding or not at runtime as follows.
Conclusion
In summary:
- Use
Activity
embedding in yourActivity
based app to support multi-pane layouts, allowing your users to see/do/experience more on large screens by making use of the extra screen real estate. - Provide a split configuration file that defines the split rules the system uses to handle embedding
Activities
in your app. - Define how embedded
Activities
should launch otherActivities
, and control how the system finishes them. - Customize split rules by using the supported options which include
splitRatio
,minSplitWidth
andclearTop
. - Register a split listener to receive updates on active splits. Don’t forget to unregister it!
- Check for split support on devices at runtime using
SplitController.isSplitSupported()
.
Notes worth mentioning from testing:
Activity
embedding only works if the split rule definessplitRatio
.- Updating
finishPrimaryWithSecondary
andfinishSecondaryWithPrimary
seemingly has no effect on the finishing behavior ofActivities
in the primary and secondary containers. (Potential bug) - If
Activities
that support embedding are run in a task that belongs to another app, then embedding will not work for them.
Want to learn more about Activity
embedding on Android? Check out:
- Official Activity embedding documentation
- Build Android UIs for any screen size
- Android 12L feature drop
[Machine Learning with tensorFlow lite in mobile apps
Techniques of machine learning in android appscodeblogs.medium.com](https://codeblogs.medium.com/android-machine-learning-9f1c7f4947ef "https://codeblogs.medium.com/android-machine-learning-9f1c7f4947ef")
[HashMap Introduction
HashMap is a class in the java.utils package that implements the Map interface.It is used to store the key-value pair.codeblogs.medium.com](https://codeblogs.medium.com/hashmap-introduction-6b4e1034ca0b "https://codeblogs.medium.com/hashmap-introduction-6b4e1034ca0b")
[Activity Launch Mode
Launch mode is an instruction for Android OS which specifies how the activity should be launched. It instructs how any…codeblogs.medium.com](https://codeblogs.medium.com/activity-launch-mode-13bf4e924296 "https://codeblogs.medium.com/activity-launch-mode-13bf4e924296")
[What can I do with kotlin : →
Well, The answers are you can any kind of development it can be like server-side, client-side web and android also this…codeblogs.medium.com](https://codeblogs.medium.com/what-can-i-do-with-kotlin-38fea7fddb5c "https://codeblogs.medium.com/what-can-i-do-with-kotlin-38fea7fddb5c")
[Application Class
What is an android application class ??codeblogs.medium.com](https://codeblogs.medium.com/application-class-d683574ac112 "https://codeblogs.medium.com/application-class-d683574ac112")
[Android Context
What is Context ? and how is it used?codeblogs.medium.com](https://codeblogs.medium.com/android-context-2371c3000c12 "https://codeblogs.medium.com/android-context-2371c3000c12")
[Android Core interview questions part 1
What are android applications components ? :-codeblogs.medium.com](https://codeblogs.medium.com/android-core-interview-questions-part-1-b5d356056432 "https://codeblogs.medium.com/android-core-interview-questions-part-1-b5d356056432")
Subscribe to my newsletter
Read articles from Laxmi kant directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by