### Get DAO and Query Data (Java) Source: https://developer.android.com/topic/libraries/architecture/room After creating the database instance, retrieve a DAO to interact with the database. This example shows how to get a UserDao and fetch all users. ```java UserDao userDao = db.userDao(); List users = userDao.getAll(); ``` -------------------------------- ### Get DAO and Query Data (Kotlin) Source: https://developer.android.com/topic/libraries/architecture/room After creating the database instance, retrieve a DAO to interact with the database. This example shows how to get a UserDao and fetch all users. ```kotlin val userDao = db.userDao() val users: List = userDao.getAll() ``` -------------------------------- ### Install APK Splits with Profile Metadata Source: https://developer.android.com/topic/performance/baselineprofiles/manually-create-measure When supporting APK splits, install each APK along with its associated `.dm` file. Ensure that the APK and `.dm` file names match for correct installation. ```bash adb install-multiple appname-base.apk appname-base.dm \ appname-split1.apk appname-split1.dm ``` -------------------------------- ### Verify Docker Installation Source: https://developer.android.com/topic/performance/power/setup-battery-historian Run this command to confirm that Docker is correctly installed on your system. A successful output indicates that Docker is ready for use. ```bash docker run hello-world ``` -------------------------------- ### Generate R8 Configuration Analyzer Report Example Source: https://developer.android.com/topic/performance/app-optimization/r8-configuration-analyzer Example command to generate the R8 Configuration Analyzer HTML report in the /tmp/r8analysis directory. ```bash // To create the /tmp/r8analysis folder. mkdir -p /tmp/r8analysis // To generate the report in the /tmp/r8analysis folder. ./gradlew assembleRelease \ -Dcom.android.tools.r8.dumpkeepradiushtmltodirectory=/tmp/r8analysis ``` -------------------------------- ### Install Python libraries for trace analysis Source: https://developer.android.com/topic/performance/tracing/profiling-manager/bulk-trace-analysis Installs the necessary Python libraries: perfetto, pandas, and plotly. ```bash pip install perfetto pandas plotly ``` -------------------------------- ### Retrieve ViewModel using Factory in Activity (Java) Source: https://developer.android.com/topic/libraries/architecture/views/viewmodel/viewmodel-factories-views This Java example demonstrates how to get a ViewModel in an Activity using `ViewModelProvider.Factory.from()`. Note the use of `MyViewModel.initializer` which might be specific to certain setups. ```Java import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.ViewModelProvider; public class MyActivity extends AppCompatActivity { MyViewModel myViewModel = new ViewModelProvider( this, ViewModelProvider.Factory.from(MyViewModel.initializer) ).get(MyViewModel.class); // Rest of Activity code } ``` -------------------------------- ### LoginActivity Dependency Setup (Java) Source: https://developer.android.com/topic/architecture/views/dependency-injection/manual-views Demonstrates how to manually instantiate LoginViewModel and its dependencies within MainActivity in Java. This involves creating Retrofit, DataSources, and UserRepository instances. ```java public class MainActivity extends Activity { private LoginViewModel loginViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // In order to satisfy the dependencies of LoginViewModel, you have to also // satisfy the dependencies of all of its dependencies recursively. // First, create retrofit which is the dependency of UserRemoteDataSource Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://example.com") .build() .create(LoginService.class); // Then, satisfy the dependencies of UserRepository UserRemoteDataSource remoteDataSource = new UserRemoteDataSource(retrofit); UserLocalDataSource localDataSource = new UserLocalDataSource(); // Now you can create an instance of UserRepository that LoginViewModel needs UserRepository userRepository = new UserRepository(localDataSource, remoteDataSource); // Lastly, create an instance of LoginViewModel with userRepository loginViewModel = new LoginViewModel(userRepository); } } ``` -------------------------------- ### LoginActivity Dependency Setup (Kotlin) Source: https://developer.android.com/topic/architecture/views/dependency-injection/manual-views Demonstrates how to manually instantiate LoginViewModel and its dependencies within LoginActivity in Kotlin. This involves creating Retrofit, DataSources, and UserRepository instances. ```kotlin class LoginActivity: Activity() { private lateinit var loginViewModel: LoginViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // In order to satisfy the dependencies of LoginViewModel, you have to also // satisfy the dependencies of all of its dependencies recursively. // First, create retrofit which is the dependency of UserRemoteDataSource val retrofit = Retrofit.Builder() .baseUrl("https://example.com") .build() .create(LoginService::class.java) // Then, satisfy the dependencies of UserRepository val remoteDataSource = UserRemoteDataSource(retrofit) val localDataSource = UserLocalDataSource() // Now you can create an instance of UserRepository that LoginViewModel needs val userRepository = UserRepository(localDataSource, remoteDataSource) // Lastly, create an instance of LoginViewModel with userRepository loginViewModel = LoginViewModel(userRepository) } } ``` -------------------------------- ### Access Entry Point Dependencies in Content Provider Source: https://developer.android.com/topic/architecture/views/dependency-injection/hilt-android-views Use `EntryPointAccessors.fromApplication` to retrieve an instance of the entry point and access the required dependencies. Ensure the component and accessor method match the `@InstallIn` annotation. ```kotlin class ExampleContentProvider: ContentProvider() { ... override fun query(...): Cursor { val appContext = context?.applicationContext ?: throw IllegalStateException() val hiltEntryPoint = EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint::class.java) val analyticsService = hiltEntryPoint.analyticsService() ... } } ``` ```java public class ExampleContentProvider extends ContentProvider { @Override public Cursor query(...) { Context appContext = getContext().getApplicationContext(); ExampleContentProviderEntryPoint hiltEntryPoint = EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint.class); AnalyticsService analyticsService = hiltEntryPoint.analyticsService(); } } ``` -------------------------------- ### Kotlin Lifecycle Example Source: https://developer.android.com/topic/architecture/views/lifecycle-views This Kotlin example demonstrates a lifecycle-aware component that starts and stops a location listener based on the activity's lifecycle. It highlights the need to handle callbacks that might occur after the activity has stopped. ```kotlin class MyActivity : AppCompatActivity() { private lateinit var myLocationListener: MyLocationListener override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) myLocationListener = MyLocationListener(this) { location -> // update UI } } override fun onStart() { super.onStart() Util.checkUserStatus { result -> // what if this callback is invoked AFTER activity is stopped? if (result) { myLocationListener.start() } } } override fun onStop() { super.onStop() myLocationListener.stop() } } ``` -------------------------------- ### Install Google Play Instant SDK via Command Line Source: https://developer.android.com/topic/google-play-instant/getting-started/instant-enabled-app-bundle Use this command to install the Google Play Instant development SDK from the command line. Ensure you navigate to the correct directory within your Android SDK. ```bash cd path/to/android/sdk/tools/bin && \ ./sdkmanager 'extras;google;instantapps' ``` -------------------------------- ### Resource References in resources.txt Source: https://developer.android.com/topic/performance/app-optimization/customize-which-resources-to-keep This example demonstrates how to inspect the resources.txt file to find references between resources, helping to understand why a resource might still be included. ```text 16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true 16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016 ``` -------------------------------- ### Custom ItemKeyedDataSource for Concert Times (Java) Source: https://developer.android.com/topic/libraries/architecture/paging/data Implement `ItemKeyedDataSource` in Java to load concert data keyed by start time. This example demonstrates the equivalent methods for Java. ```java public class ConcertTimeDataSource extends ItemKeyedDataSource { @NonNull @Override public Date getKey(@NonNull Concert item) { return item.getStartTime(); } @Override public void loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback callback) { List items = fetchItems(params.key, params.requestedLoadSize); callback.onResult(items); } @Override public void loadAfter(@NonNull LoadParams params, @NonNull LoadCallback callback) { List items = fetchItemsAfter(params.key, params.requestedLoadSize); callback.onResult(items); } } ``` -------------------------------- ### Create Proto DataStore Instance Source: https://developer.android.com/topic/libraries/architecture/datastore Create an instance of Proto DataStore using the dataStore delegate. Specify the file name and the proto serializer. ```kotlin val Context.dataStore: DataStore by dataStore( fileName = "settings.pb", serializer = SettingsSerializer, ) ``` -------------------------------- ### Custom ItemKeyedDataSource for Concert Times (Kotlin) Source: https://developer.android.com/topic/libraries/architecture/paging/data Implement `ItemKeyedDataSource` to load concert data keyed by start time. This example shows how to define `getKey`, `loadInitial`, and `loadAfter` methods. ```kotlin class ConcertTimeDataSource() : ItemKeyedDataSource() { override fun getKey(item: Concert) = item.startTime override fun loadInitial( params: LoadInitialParams, callback: LoadInitialCallback) { val items = fetchItems(params.requestedInitialKey, params.requestedLoadSize) callback.onResult(items) } override fun loadAfter( params: LoadParams, callback: LoadCallback) { val items = fetchItemsAfter( date = params.key, limit = params.requestedLoadSize) callback.onResult(items) } } ``` -------------------------------- ### Start Activity for Result (Java) Source: https://developer.android.com/topic/libraries/architecture/views/activity-lifecycle-views Initiates an activity to get a result back and handles the result in `onActivityResult`. Use `startActivityForResult` to launch an activity and `PICK_CONTACT_REQUEST` as a unique identifier for the call. ```Java public class MyActivity extends Activity { // ... static final int PICK_CONTACT_REQUEST = 0; public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // When the user center presses, let them pick a contact. startActivityForResult( new Intent(Intent.ACTION_PICK, new Uri("content://contacts")), PICK_CONTACT_REQUEST); return true; } return false; } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PICK_CONTACT_REQUEST) { if (resultCode == RESULT_OK) { // A contact was picked. Display it to the user. startActivity(new Intent(Intent.ACTION_VIEW, data)); } } } } ``` -------------------------------- ### Install APK and Profile Together Source: https://developer.android.com/topic/performance/baselineprofiles/manually-create-measure Install an APK along with its corresponding profile metadata file (`.dm`). This method is used on devices running API 28 and later for sideloading Baseline Profiles. ```bash # Install APK and the profile together adb install-multiple appname-release.apk appname-release.dm ``` -------------------------------- ### Instantiate ViewModel with Custom CreationExtras Source: https://developer.android.com/topic/libraries/architecture/views/viewmodel/viewmodel-factories-views Demonstrates how to instantiate a ViewModel using a custom factory and `CreationExtras`. This example shows how to set a custom dependency using a `CreationExtras.Key` within `MutableCreationExtras`. ```kotlin import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelStoreOwner import androidx.lifecycle.viewmodel.CreationExtras import androidx.lifecycle.viewmodel.MutableCreationExtras // ... // Use from ComponentActivity, Fragment, NavBackStackEntry, // or another ViewModelStoreOwner. val viewModelStoreOwner: ViewModelStoreOwner = this val myViewModel: MyViewModel = ViewModelProvider.create( viewModelStoreOwner, factory = MyViewModel.Factory, extras = MutableCreationExtras().apply { set(MyViewModel.MY_REPOSITORY_KEY, myRepository) }, )[MyViewModel::class] ``` -------------------------------- ### Start Activity for Result (Kotlin) Source: https://developer.android.com/topic/libraries/architecture/views/activity-lifecycle-views Initiates an activity to get a result back and handles the result in `onActivityResult`. Use `startActivityForResult` to launch an activity and `PICK_CONTACT_REQUEST` as a unique identifier for the call. ```Kotlin class MyActivity : Activity() { // ... override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // When the user center presses, let them pick a contact. startActivityForResult( Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")), PICK_CONTACT_REQUEST) return true } return false } override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { when (requestCode) { PICK_CONTACT_REQUEST -> if (resultCode == RESULT_OK) { // A contact was picked. Display it to the user. startActivity(Intent(Intent.ACTION_VIEW, intent?.data)) } } } companion object { internal val PICK_CONTACT_REQUEST = 0 } } ``` -------------------------------- ### Pull-based Synchronization with Jetpack Paging Source: https://developer.android.com/topic/architecture/data-layer/offline-first Example of a repository and ViewModel setup for pull-based synchronization using Jetpack Paging Library and RemoteMediator. This pattern is suitable for data that can be fetched on demand. ```kotlin class FeedRepository(...) { fun feedPagingSource(): PagingSource { ... } } class FeedViewModel( private val repository: FeedRepository ) : ViewModel() { private val pager = Pager( config = PagingConfig( pageSize = NETWORK_PAGE_SIZE, enablePlaceholders = false ), remoteMediator = FeedRemoteMediator(...), pagingSourceFactory = feedRepository::feedPagingSource ) val feedPagingData = pager.flow } ``` -------------------------------- ### Benchmark Results Comparison Source: https://developer.android.com/topic/performance/baselineprofiles/create-baselineprofile Compare benchmark results for startup compilation with and without Baseline Profiles. This helps in measuring the speed improvements provided by the profile. ```text StartupBenchmarks_startupCompilationBaselineProfiles timeToInitialDisplayMs min 161.8, median 178.9, max 194.6 StartupBenchmarks_startupCompilationNone timeToInitialDisplayMs min 184.7, median 196.9, max 202.9 ``` -------------------------------- ### Setup Preferences DataStore (Groovy) Source: https://developer.android.com/topic/libraries/architecture/datastore Add the Preferences DataStore library to your Gradle file for SharedPreferences-like APIs. Includes optional RxJava support. ```groovy dependencies { // Preferences DataStore (SharedPreferences like APIs) implementation "androidx.datastore:datastore-preferences:1.2.1" // Alternatively - without an Android dependency. implementation "androidx.datastore:datastore-preferences-core:1.2.1" } ``` ```groovy dependencies { // optional - RxJava2 support implementation "androidx.datastore:datastore-preferences-rxjava2:1.2.1" // optional - RxJava3 support implementation "androidx.datastore:datastore-preferences-rxjava3:1.2.1" } ``` -------------------------------- ### Get ViewModel Scoped to a Specific ViewModelStoreOwner (Compose) Source: https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-apis Obtain a ViewModel instance scoped to a specific `ViewModelStoreOwner` by passing it as a parameter to the `viewModel()` function. This is useful when you need to control the scope explicitly, for example, using a parent `NavBackStackEntry`. ```kotlin import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.ViewModelStoreOwner @Composable fun MyScreen( // A custom owner passed in, such as a parent NavBackStackEntry customOwner: ViewModelStoreOwner, // The ViewModel is now scoped to the provided customOwner viewModel: MyViewModel = viewModel(viewModelStoreOwner = customOwner) ) { /* ... */ } ``` -------------------------------- ### Observing Paged Data with LiveData in Java Source: https://developer.android.com/topic/libraries/architecture/paging This Java snippet shows the equivalent setup for observing paged data using LiveData. It mirrors the Kotlin example with Room DAO, ViewModel, and Activity configurations for RecyclerView integration. ```java @Dao public interface ConcertDao { // The Integer type parameter tells Room to use a PositionalDataSource // object, with position-based loading under the under. @Query("SELECT * FROM concerts ORDER BY date DESC") DataSource.Factory concertsByDate(); } public class ConcertViewModel extends ViewModel { private ConcertDao concertDao; public final LiveData> concertList; public ConcertViewModel(ConcertDao concertDao) { this.concertDao = concertDao; concertList = new LivePagedListBuilder<>( concertDao.concertsByDate(), /* page size */ 50).build(); } } public class ConcertActivity extends AppCompatActivity { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ConcertViewModel viewModel = new ViewModelProvider(this).get(ConcertViewModel.class); RecyclerView recyclerView = findViewById(R.id.concert_list); ConcertAdapter adapter = new ConcertAdapter(); viewModel.concertList.observe(this, adapter::submitList); recyclerView.setAdapter(adapter); } } public class ConcertAdapter extends PagedListAdapter { protected ConcertAdapter() { super(DIFF_CALLBACK); } @Override public void onBindViewHolder(@NonNull ConcertViewHolder holder, int position) { Concert concert = getItem(position); if (concert != null) { holder.bindTo(concert); } else { // Null defines a placeholder item - PagedListAdapter automatically // invalidates this row when the actual object is loaded from the // database. holder.clear(); } } private static DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { // Concert details may have changed if reloaded from the database, // but ID is fixed. @Override public boolean areItemsTheSame(Concert oldConcert, Concert newConcert) { return oldConcert.getId() == newConcon.getId(); } @Override public boolean areContentsTheSame(Concert oldConcert, Concert newConcert) { return oldConcert.equals(newConcert); } }; } ``` -------------------------------- ### Register and Release Reporters for Background Tasks (Java) Source: https://developer.android.com/topic/performance/launch-time This Java example demonstrates how to use `FullyDrawnReporter` to manage background tasks. Reporters are added before a task starts and removed upon completion, ensuring that the `reportFullyDrawn()` call accounts for the task's duration. ```java public class MainActivity extends ComponentActivity { private FullyDrawnReporter fullyDrawnReporter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); fullyDrawnReporter = getFullyDrawnReporter(); fullyDrawnReporter.addOnReportDrawnListener(() -> { // Trigger the UI update. return Unit.INSTANCE; }); new Thread(new Runnable() { @Override public void run() { fullyDrawnReporter.addReporter(); // Do the background work. fullyDrawnReporter.removeReporter(); } }).start(); new Thread(new Runnable() { @Override public void run() { fullyDrawnReporter.addReporter(); // Do the background work. fullyDrawnReporter.removeReporter(); } }).start(); } } ``` -------------------------------- ### Setup Preferences DataStore (Kotlin) Source: https://developer.android.com/topic/libraries/architecture/datastore Add the Preferences DataStore library to your Gradle file for SharedPreferences-like APIs. Includes optional RxJava support. ```kotlin dependencies { // Preferences DataStore (SharedPreferences like APIs) implementation("androidx.datastore:datastore-preferences:1.2.1") // Alternatively - without an Android dependency. implementation("androidx.datastore:datastore-preferences-core:1.2.1") } ``` ```kotlin dependencies { // optional - RxJava2 support implementation("androidx.datastore:datastore-preferences-rxjava2:1.2.1") // optional - RxJava3 support implementation("androidx.datastore:datastore-preferences-rxjava3:1.2.1") } ``` -------------------------------- ### Start Spring Animation (Java) Source: https://developer.android.com/topic/libraries/support-library/preview/spring-animation Starts a spring animation for the TRANSLATION_Y property of a View using Java. Ensure the animation is created and configured before calling `start()`. ```java final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Starting the animation anim.start(); … ``` -------------------------------- ### Measure Unoptimized App Startup Source: https://developer.android.com/topic/performance/baselineprofiles/manually-create-measure Measure the unoptimized app startup time, corresponding to the 'Time to initial display' metric. This is a baseline measurement before applying optimizations. ```bash PACKAGE_NAME=com.example.app # Force Stop App adb shell am force-stop $PACKAGE_NAME # Reset compiled state adb shell cmd package compile --reset $PACKAGE_NAME # Measure App startup # This corresponds to `Time to initial display` metric. adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \ | grep "TotalTime" ``` -------------------------------- ### Start Spring Animation (Kotlin) Source: https://developer.android.com/topic/libraries/support-library/preview/spring-animation Starts a spring animation for the TRANSLATION_Y property of a View using Kotlin. Ensure the animation is created and configured before calling `start()`. ```kotlin findViewById(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Starting the animation start() … } } ``` -------------------------------- ### Hilt DataStore Provider Example Source: https://developer.android.com/topic/libraries/architecture/datastore An example of providing a singleton DataStore instance per process using Hilt dependency injection. This ensures that only one DataStore instance is created within a given process. ```kotlin @Provides @Singleton fun provideDataStore(@ApplicationContext context: Context): DataStore = MultiProcessDataStoreFactory.create(...) ``` -------------------------------- ### Presenter Class Example (Java) Source: https://developer.android.com/topic/libraries/data-binding/expressions Example of a presenter class with an event handler method in Java. ```java public class Presenter { public void onSaveClick(Task task){} } ``` -------------------------------- ### Generate Startup Profile with Deep Link Source: https://developer.android.com/topic/performance/baselineprofiles/dex-layout-optimizations Use this code to generate a Startup Profile that includes launching the app from the home screen and navigating to a specific deep link. Ensure `includeInStartupProfile` is set to `true`. ```kotlin import androidx.benchmark.macro.junit4.BaselineProfileRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.LargeTest import android.content.Intent import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @LargeTest class BaselineProfileGenerator { @get:Rule val rule = BaselineProfileRule() @Test fun generate() { rule.collect( packageName = "com.example.app", includeInStartupProfile = true ) { uiAutomator { // Launch directly into the NEWS_FEED using startActivityIntent startIntent(Intent().apply { setPackage(packageName) setAction("com.example.app.NEWS_FEED") }) } } } ``` -------------------------------- ### Presenter Class Example (Kotlin) Source: https://developer.android.com/topic/libraries/data-binding/expressions Example of a presenter class with an event handler method in Kotlin. ```kotlin class Presenter { fun onSaveClick(task: Task){} } ``` -------------------------------- ### Estimate Cold Startup Time Source: https://developer.android.com/topic/performance/tracing/profiling-manager/querying-profiles Demonstrates using the custom SQL functions to estimate cold startup time by measuring the duration between 'bindApplication' and the first 'Choreographer#doFrame'. This metric estimates time to first frame (TTFF). ```sql -- Using these functions we can estimate cold startup time by generating a slice between bindApplication and first frame. SELECT * from generate_start_to_end_slices('bindApplication','*Choreographer#doFrame [0-9]*', true) ``` -------------------------------- ### Example String Array Definition Source: https://developer.android.com/topic/architecture/views/resources/string-resource-views An example of a string array resource named 'planets_array' saved in res/values/strings.xml. ```xml Mercury Venus Earth Mars ``` -------------------------------- ### Launch coroutine when Lifecycle is STARTED Source: https://developer.android.com/topic/libraries/architecture/views/coroutines-views Use `whenStarted` to run a coroutine block only when the associated Lifecycle is at least in the STARTED state. The code within the block will execute when the fragment starts and can safely perform operations like fragment transactions. ```kotlin class MyFragment: Fragment { init { // Notice that we can safely launch in the constructor of the Fragment. lifecycleScope.launch { whenStarted { // The block inside will run only when Lifecycle is at least STARTED. // It will start executing when fragment is started and // can call other suspend methods. loadingView.visibility = View.VISIBLE val canAccess = withContext(Dispatchers.IO) { checkUserAccess() } // When checkUserAccess returns, the next line is automatically // suspended if the Lifecycle is not *at least* STARTED. // We could safely run fragment transactions because we know the // code won't run unless the lifecycle is at least STARTED. loadingView.visibility = View.GONE if (canAccess == false) { findNavController().popBackStack() } else { showContent() } } // This line runs only after the whenStarted block above has completed. } } } ```