<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Hicham Boushaba</title>
    <description>The latest articles on Forem by Hicham Boushaba (@hichamboushaba).</description>
    <link>https://forem.com/hichamboushaba</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F740662%2F2ba8e518-aa98-41fe-9653-ba9d071a1dd4.jpeg</url>
      <title>Forem: Hicham Boushaba</title>
      <link>https://forem.com/hichamboushaba</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hichamboushaba"/>
    <language>en</language>
    <item>
      <title>Consuming Activity Results using coroutines: Part 2</title>
      <dc:creator>Hicham Boushaba</dc:creator>
      <pubDate>Tue, 07 Dec 2021 11:21:00 +0000</pubDate>
      <link>https://forem.com/hichamboushaba/consuming-activity-results-using-coroutines-part-2-54mf</link>
      <guid>https://forem.com/hichamboushaba/consuming-activity-results-using-coroutines-part-2-54mf</guid>
      <description>&lt;p&gt;This is the second post of a 2 parts article on how we can convert and consume Activity Results using coroutines.&lt;br&gt;
In the &lt;a href="https://dev.to/hichamboushaba/consuming-activity-results-using-coroutines-part-1-2j57"&gt;first part&lt;/a&gt;, we were able to create a &lt;a href="https://gist.github.com/hichamboushaba/440939bf85300b1fe634580d19bf018d#file-permissionmanager-kt"&gt;component&lt;/a&gt; that allowed us to convert the Activity Result's contract &lt;a href="https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts.RequestMultiplePermissions"&gt;RequestMultiplePermissions&lt;/a&gt; to a Coroutine, while still able to handle Activity Recreation and process-death scenarios.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generalize our code for all Activity Results
&lt;/h2&gt;

&lt;p&gt;When reviewing the code we had for our PermissionManager class, the only specific parts related to permissions were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The instantiation of &lt;code&gt;RequestMultiplePermissions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The mapping of the result to our defined sealed class.&lt;/li&gt;
&lt;li&gt;Saving the permissions' list to the saved state, and using it as the flag for deciding if there is any pending operation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So for designing our component that can be used to consume all Activity Results, we just need to generalize or remove the above points.&lt;br&gt;
The first two points are straight forward, as we are aiming for a generic component here, we'll just remove them, so we'll pass the instance of our &lt;code&gt;ActivityResultContract&lt;/code&gt; to our function, and we'll make it return the same type as defined by the contract. which means having a signature for our main function as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;suspend fun &amp;lt;I, O, C : ActivityResultContract&amp;lt;I, O&amp;gt;&amp;gt; requestResult(
        contract: C,
        input: I
    ): O?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For the third point, we have many ways for handling it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using a simple boolean to tell us if there is any pending operation.
This would work for most cases, but it has one downside, if a process-death occurs, and in the ViewModel's side we don't handle it, our component will still think that there is a pending operation, which means if we request a different type of results, it'll get stuck.&lt;/li&gt;
&lt;li&gt;By saving the contract's class name, and comparing against it, this is a simple way for doing it, and would work for the majority of cases, although it may still break on a very specific case: if the ViewModel doesn't handle process-death, and we request another result using the same type of Contract, but using a different input, we'll probably return the wrong result.&lt;/li&gt;
&lt;li&gt;By saving both the contract's class name and the input, and while this the ultimate solution, the comparison of the input against a saved value won't be straight forward, since it's a generic type, and we don't know if it has a valid &lt;code&gt;equals&lt;/code&gt; implementation or not.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I opted for the option two, since the failure scenario is a very far corner case, and when using the SavedStateHandle correctly to save state, it won't occur at all, let me know what you think about this choice in the comments.&lt;/p&gt;

&lt;p&gt;With all of this, we can have our component now:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h2&gt;
  
  
  Meet the library SuspendActivityResult
&lt;/h2&gt;

&lt;p&gt;After starting the article, I decided to publish this component as a library for anyone interested, it's available in the same &lt;a href="https://github.com/hichamboushaba/SuspendActivityResult"&gt;repo&lt;/a&gt;.&lt;br&gt;
The Activity Result can be requested either using the low level API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;uri&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ActivityResultManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;requestResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;contract&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GetContent&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"image/*"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or using the extensions for the built-in &lt;a href="https://developer.android.com/reference/kotlin/androidx/activity/result/contract/ActivityResultContracts"&gt;ActivityResultContracts&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;uri&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ActivityResultManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"image/*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/hichamboushaba/SuspendActivityResult/tree/master/app"&gt;example&lt;/a&gt; app has samples for using it for permissions and  other activity results, and it has a sample for using it for a custom &lt;code&gt;ActivityResultContract&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you have any remarks or questions regarding the code or the API, please drop them in the comments section, I hope the library can be useful to some people. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Consuming Activity Results using coroutines: Part 1</title>
      <dc:creator>Hicham Boushaba</dc:creator>
      <pubDate>Tue, 16 Nov 2021 19:46:57 +0000</pubDate>
      <link>https://forem.com/hichamboushaba/consuming-activity-results-using-coroutines-part-1-2j57</link>
      <guid>https://forem.com/hichamboushaba/consuming-activity-results-using-coroutines-part-1-2j57</guid>
      <description>&lt;p&gt;Handling results from other Activies was always a tedious task: you need to override callbacks in the Activity/Fragment, and you need to manage the different request codes, and when you get a result, you need to parse it and this was never easy*.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;* will the returned Uri be in &lt;code&gt;intent.data&lt;/code&gt; or passed in the &lt;code&gt;extras&lt;/code&gt; (looking at you &lt;code&gt;RingtoneManager.EXTRA_RINGTONE_PICKED_URI&lt;/code&gt;)? what's the key of the returned data inside the &lt;code&gt;extras&lt;/code&gt; and what's its type?...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To solve the above issues, the Android team introduced the androidx's &lt;a href="https://developer.android.com/training/basics/intents/result"&gt;Activity Result API&lt;/a&gt;, it offers a nicer API, and it's easily extendable by writing custom &lt;code&gt;Contracts&lt;/code&gt;, but it still requires doing most of the work on the UI layer, which means lots of going back and forth between the View and the ViewModel for simple tasks.&lt;/p&gt;

&lt;p&gt;This post is the first of two posts where we'll explore how we can optimize the API, by converting it to suspendable functions, and allowing it to be consumed by the ViewModel instead of the UI layer.&lt;br&gt;
On this first part, we'll use permissions as an example, for this We'll start by showing an example on how the Activity Result API can be used to handle them, and then we'll try to write the new suspendable API together, and see how it can improve the readability of our code.&lt;br&gt;
The code of the example can be found in this &lt;a href="https://github.com/hichamboushaba/SuspendActivityResult"&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Part 2 is available &lt;a href="https://dev.to/hichamboushaba/consuming-activity-results-using-coroutines-part-2-54mf"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Activity Result API in play
&lt;/h2&gt;

&lt;p&gt;Using the Activity Result API is quite simple, you just need to register an &lt;a href="https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContract"&gt;ActivityResultContract&lt;/a&gt; with your Activity/Fragment, while offering a callback that will be called when the result is delivered:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
The registration will return an &lt;a href="https://developer.android.com/reference/kotlin/androidx/activity/result/ActivityResultLauncher?hl=en"&gt;ActivityResultLauncher&lt;/a&gt; which you will use whenever you need to request the result&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
But while it's simple now, it becomes a bit complicated when we try to hook everything with the ViewModel, as it would require multiple two-way communication steps for something simple as the permission:&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
This is all while omitting some necessary parts, especially dealing with configuration changes and process-death.&lt;br&gt;
For a full example, check the following sample &lt;a href="https://github.com/hichamboushaba/SuspendActivityResult/tree/88ea62fdf29fb3a3cf46f33cffb87f0742167d96/app/src/main/java/com/hicham/activityresult/permission/regular"&gt;fragment&lt;/a&gt;. 

&lt;p&gt;I feel like with this code, the View is doing so much, and we can't easily reuse this code if we need to request the same permission in multiple parts of the app.&lt;/p&gt;
&lt;h2&gt;
  
  
  Converting the Activity Result to suspendable functions: Permissions as an example
&lt;/h2&gt;

&lt;p&gt;On this part, we'll try to move the logic of Activity Result API to another layer, to allow it to be consumed by the ViewModel.&lt;br&gt;
Our goal is to have something similar to this by the end:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's get started, since the Activity Result API needs a reference to the Activity or the Fragment, the first thing we'll need, is a reference to the current Activity, we can use the function &lt;code&gt;registerActivityLifecycleCallbacks&lt;/code&gt; to listen to Activity lifecycle changes, and keep a track of the latest one, a short example on how we can achieve this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
This class needs to be a singleton, and initiated in the Application's onCreate.&lt;br&gt;
With this in hand, we can now "naively" write something like this easily:&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Before testing our code, let's take a moment to check what it does:

&lt;ul&gt;
&lt;li&gt;We use a &lt;code&gt;suspendCancellableCoroutine&lt;/code&gt; to convert the Activity result to a suspendable function.&lt;/li&gt;
&lt;li&gt;We can't register our &lt;code&gt;Contract&lt;/code&gt; directly using the function &lt;code&gt;registerForActivityResult&lt;/code&gt;, as it requires to be called before &lt;code&gt;onCreate&lt;/code&gt;, instead we use the &lt;code&gt;activityResultRegistry&lt;/code&gt; directly, and here we just need to handle the unregistering ourself, so we use the &lt;code&gt;finally&lt;/code&gt; block to make sure we are unregistering in either a cancellation or completion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's test the code: &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;br&gt;
When testing this, we'll see that it works well, until you rotate your phone, or a process-death occurs, when we'll leak the activity, and also we won't be able to recover to continue handling the result.

&lt;h4&gt;
  
  
  Fix the issue for screen rotation
&lt;/h4&gt;

&lt;p&gt;This happens because we are capturing the current Activity in a variable, this variable stays available for the whole function's lifetime, which is longer than the Activity's lifecycle. To solve this, we need a way to listen to the Activity changes, to be able to cancel the previous &lt;code&gt;block&lt;/code&gt; and unregister the &lt;code&gt;Contract&lt;/code&gt;, then re-register with the new Activity, so we need to change our ActivityProvider's implementation to offer a Flow instead of a single variable, which can bee easily done using &lt;code&gt;MutableStateFlow&lt;/code&gt;, for full code check &lt;a href="https://github.com/hichamboushaba/SuspendActivityResult/blob/master/app/src/main/java/com/hicham/activityresult/ActivityProvider.kt"&gt;this&lt;/a&gt;.&lt;br&gt;
With those changes, we can now use Flow's &lt;code&gt;mapLatest&lt;/code&gt; operator to handle registering our &lt;code&gt;Contract&lt;/code&gt;, and unregistering it when the block is cancelled, since it would occur everytime the &lt;code&gt;Activity&lt;/code&gt; wach changed, which would give something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Let's examine what the code does:

&lt;ul&gt;
&lt;li&gt;We capture the value of the key outside of the Flow, to make sure we keep using the same value for other Activities.&lt;/li&gt;
&lt;li&gt;We have a variable &lt;code&gt;isLaunched&lt;/code&gt; to let us know that the &lt;code&gt;ActivityResultLauncher&lt;/code&gt; has been already launched, to avoid re-submitting the Intent or permission request.&lt;/li&gt;
&lt;li&gt;the suspendable funtion passed to &lt;code&gt;mapLatest&lt;/code&gt; will be cancelled each time the upstream Flow emits a new value, so it does exactly what we need, it suspends waiting for the Activity Result, but if the &lt;code&gt;Activity&lt;/code&gt; was changed before, it cancels the current block, and starts a new one with the new Activity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When testing the new code, it works pretty well on screen rotations, we can continue the Flow from where we left, great.&lt;br&gt;
Except that it has an issue, if a process-death occurs, or the Activity was destroyed to release memory (or when "Don't keep activities" option is enabled), we can't recover even if our ViewModel uses &lt;code&gt;SavedStateHandle&lt;/code&gt; to restore its state, since the &lt;code&gt;viewModelScope&lt;/code&gt; will be cancelled, and our function will lose its state, which takes us to the last part of this article, how we can use the Activity's &lt;code&gt;SavedStateRegistry&lt;/code&gt; to save our state, and make sure that even when we make a second call to &lt;code&gt;requestPermissions&lt;/code&gt; it will continue from where it left.&lt;/p&gt;

&lt;h4&gt;
  
  
  Saving the state
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;ComponentActivity&lt;/code&gt; from androidx has a component called &lt;code&gt;SavedStateRegistry&lt;/code&gt; that allows plugging in custom components to save additional data and retrieve it later, and this is exactly what we need here, since we can't use the Activity's callbacks, we'll use it to keep track of the last key we used to register our &lt;code&gt;Contract&lt;/code&gt;, to be able to intercept the Activity Result even after process-death:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
The code seems complicated, but it differs from the previous step in only the fact that it tries to restore the last used key from the &lt;code&gt;SavedStateRegistry&lt;/code&gt;, and also it registers our &lt;code&gt;SavedStateProvider&lt;/code&gt; to save the state when needed.&lt;br&gt;
If we test the code now, using a &lt;code&gt;ViewModel&lt;/code&gt; that uses &lt;code&gt;SavedStateHandle&lt;/code&gt; for saving/restoring its state correctly, we'll see that we continue to receive the Activity Result correctly even after a process-death.

&lt;h4&gt;
  
  
  What we can do with this component now
&lt;/h4&gt;

&lt;p&gt;Being able to use a suspendable function like this here, makes it way easier to extract our logic into a reusable components, for example if your app requests the permission from multiple areas, and uses the same logic for showing the rationale or handling a pemanent denial, you'll be able to create a component or a usecase that handles this for you, without having to repeat it on each Fragment/Activity.&lt;br&gt;
For example a class like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
This component is self contained, and allows to handle the whole permission request Flow, and can be reused on every screen easily.&lt;br&gt;
A full example can be found &lt;a href="https://github.com/hichamboushaba/SuspendActivityResult/blob/master/app/src/main/java/com/hicham/activityresult/permission/LocationPermissionController.kt"&gt;here&lt;/a&gt;.

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To sum up, the callback aspect of the new Result Activity API allows it to be converted to suspendable functions relatively easy, instead of needing an intermediate Fragment or Activity for handling the callbacks (as many libraries do), and this conversion made it easier to extract pieces of the logic to their own component. But the code is not tested against all scenarios, especially when the app has multiple activities, so we'll try to check this in the next part, and we'll try to generalize what we did with permissions so far for all the Activity Result Contracts.&lt;br&gt;
Please let me know in the comments if you have any remarks about this solution, thanks for your time.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>coroutines</category>
    </item>
    <item>
      <title>Making cold Flows lifecycle-aware</title>
      <dc:creator>Hicham Boushaba</dc:creator>
      <pubDate>Sat, 30 Oct 2021 17:37:01 +0000</pubDate>
      <link>https://forem.com/hichamboushaba/making-callback-flows-lifecycle-aware-2dai</link>
      <guid>https://forem.com/hichamboushaba/making-callback-flows-lifecycle-aware-2dai</guid>
      <description>&lt;p&gt;With the introduction of SharedFlow and StateFlow, many developers are migrating from LiveData in the UI layer, to take advantage of the goodies of the Flow API, and for a more consistent API accross all layers, but sadly, and as Christophe Beyls explains on his &lt;a href="https://bladecoder.medium.com/kotlins-flow-in-viewmodels-it-s-complicated-556b472e281a"&gt;post&lt;/a&gt;, the migration is complicated when the view's lifecycle enters into equation.&lt;br&gt;
The version 2.4 of &lt;code&gt;lifecycle:lifecycle-runtime-ktx&lt;/code&gt; introduced APIs to help on this side: &lt;code&gt;repeatOnLifecycle&lt;/code&gt; and &lt;code&gt;flowWithLifecycle&lt;/code&gt; (to learn more about those, check the article: &lt;a href="https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda"&gt;A safer way to collect flows from Android UIs&lt;/a&gt;), on this article, we'll try them, and we'll dicuss a minor issue that they introduce in some cases, and we'll see if we can come up with a more flexible solution.&lt;/p&gt;
&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;To explain the problem, let's imagine we have a sample app that listens to location updates when it's active, and whenever a new location is available, it'll make an API call to retrieve some nearby locations.&lt;br&gt;
So for listening to location updates, we'll write a LocationObserver class that offers a cold Flow returning them&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocationObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;observeLocationUpdates&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callbackFlow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"observing location updates"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocationServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFusedLocationProviderClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;locationRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocationRequest&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPriority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocationRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PRIORITY_HIGH_ACCURACY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFastestInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;locationCallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;LocationCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onLocationResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locationResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LocationResult&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locationResult&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"got location ${locationResult.lastLocation}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="nf"&gt;trySend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locationResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastLocation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestLocationUpdates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;locationRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;locationCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Looper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMainLooper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="nf"&gt;awaitClose&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"stop observing location updates"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeLocationUpdates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locationCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then we'll use this class in our ViewModel&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AndroidViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;locationObserver&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocationObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;hasLocationPermission&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableStateFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;locationUpdates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hasLocationPermission&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMapLatest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;locationObserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observeLocationUpdates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;viewState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ViewState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;locationUpdates&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapLatest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;nearbyLocations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchNearbyLocations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nc"&gt;ViewState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;nearbyLocations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nearbyLocations&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onLocationPermissionGranted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;hasLocationPermission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;For the sake of simplicity, we are using an &lt;code&gt;AndroidViewModel&lt;/code&gt; to have access to the &lt;code&gt;Context&lt;/code&gt; directly, and we won't handle different edge cases about location permissions and settings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, all we have to do in our Fragment, is to listen to the react to the &lt;code&gt;viewState&lt;/code&gt; updates, and update the UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;viewLifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lifecycleScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchWhenStarted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;viewState&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;viewState&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where the &lt;code&gt;FragmentMainBinding#render&lt;/code&gt; is an extension that can update the UI.&lt;/p&gt;

&lt;p&gt;Now if we try to run the app, when we put it to the background, we'll see that the LocationObserver is still listening to location updates, then fetching the nearby places, even though the UI is ignoring them.&lt;/p&gt;

&lt;p&gt;Our first attempt to solve this, is to use the new API &lt;code&gt;flowWithLifecycle&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;viewLifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lifecycleScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchWhenStarted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;viewState&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flowWithLifecycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewLifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lifecycle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;viewState&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run the app, now, we'll notice that it prints the following line to Logcat each time it goes to background&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D/LocationObserver: stop observing location updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the new APIs fix the issue, but there is an issue, whenever the app goes to background then we come back, we lose the data we had before, and we hit the API another time even if the location hasn't changed, this occurs because  &lt;code&gt;flowWithLifecycle&lt;/code&gt; will cancel the upstream each time the used &lt;code&gt;lifecycle&lt;/code&gt; goes below the passed &lt;code&gt;State&lt;/code&gt; (which is &lt;code&gt;Started&lt;/code&gt; for us) and restart it again when the state is restaured.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution using the official APIs
&lt;/h3&gt;

&lt;p&gt;The official solution while keeping using &lt;code&gt;flowWithLifecycle&lt;/code&gt; is explained in Jose Alcérreca's &lt;a href="https://medium.com/androiddevelopers/migrating-from-livedata-to-kotlins-flow-379292f419fb"&gt;article&lt;/a&gt;, and it's to use &lt;code&gt;stateIn&lt;/code&gt; but with a special &lt;code&gt;timeout&lt;/code&gt; set to 5 seconds to account for configuration changes, so we need to add the following statement to our viewState's Flow to this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;stateIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewModelScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;started&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SharingStarted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WhileSubscribed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopTimeoutMillis&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000L&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;initialValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works well, except, the stopping/restarting of the Flow each time the app goes to background creates another issue, let's say for example that we don't need to fetch the nearby places unless the location has changed by a minimum distance, so let's change our code to the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;viewState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ViewState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;locationUpdates&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;distinctUntilChanged&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;distanceTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapLatest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;nearbyLocations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchNearbyLocations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nc"&gt;ViewState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;nearbyLocations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nearbyLocations&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stateIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewModelScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;started&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SharingStarted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WhileSubscribed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopTimeoutMillis&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000L&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;initialValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run the app now, then we put it to background for longer than 5 seconds, and re-open it, we will notice that the we re-fetch the nearby locations even if the location didn't change at all, and while this is not a big issue for most cases, it can be costly on some situations: slow network, or slow APIs, or heavy calculations...&lt;/p&gt;

&lt;h3&gt;
  
  
  An alternative solution: making the Flows lifecycle-aware
&lt;/h3&gt;

&lt;p&gt;What if we could make our &lt;code&gt;locationUpdates&lt;/code&gt; flow lifecycle-aware, to stop it without any explicit interaction from the Fragment? This way, we will be able to stop listening to location updates, without having to restart the whole Flow, and re-run all the intermediate operators if the location didn't change, and we could even collect our &lt;code&gt;viewState&lt;/code&gt; Flow regularly using &lt;code&gt;launchWhenStarted&lt;/code&gt;, since we will be sure it won't run as we are not emitting any locations.&lt;/p&gt;

&lt;p&gt;If only we can have an internal hot flow inside our ViewModel that let's us observe the View's state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lifeCycleState&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableSharedFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Lifecycle&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;replay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onBufferOverflow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BufferOverflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DROP_OLDEST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we would be able to have an extension that stops then restarts our upstream Flow depending on the lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenAtLeast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requiredState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lifeCycleState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAtLeast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requiredState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;distinctUntilChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMapLatest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// flatMapLatest will take care of cancelling the upstream Flow&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;emptyFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actually, we can implement this using &lt;code&gt;LifecycleEventObserver&lt;/code&gt; API&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lifecycleObserver&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;LifecycleEventObserver&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onStateChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lifeCycleState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tryEmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;targetState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;targetState&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DESTROYED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which we can use to hook up to the Fragment's lifecycle events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;startObservingLifecycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lifecycle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Lifecycle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lifecycleObserver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having this, we can now update our &lt;code&gt;locationUpdates&lt;/code&gt; Flow to the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;locationUpdates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hasLocationPermission&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMapLatest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;locationObserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observeLocationUpdates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenAtLeast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Lifecycle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STARTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we get to observe our &lt;code&gt;viewState&lt;/code&gt; Flow regularly in the Fragment, without worrying about keeping the GPS on when the app goes to the background&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;viewLifecycleOwner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lifecycleScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchWhenStarted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;viewState&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;viewState&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extension &lt;code&gt;whenAtLeast&lt;/code&gt; is flexible in the sense that it can be applied to any Flow in the chain, and not only during the collection, and as we saw, applying it to the upstream triggering Flow (location updates in our case), resulted in less calculations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The intermediate operators including the nearby places fetching doesn't run unless needed.&lt;/li&gt;
&lt;li&gt;We won't re-emit the result to the UI on coming back from background since we won't cancel the collection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to check the full code on Github: &lt;a href="https://github.com/hichamboushaba/FlowLifecycle"&gt;https://github.com/hichamboushaba/FlowLifecycle&lt;/a&gt;, and the full code contains a &lt;a href="https://github.com/hichamboushaba/FlowLifecycle/blob/13a81082fe7fe50da483dfa997b7691d497d83ca/app/src/test/java/com/hicham/flowlifecycle/SampleTest.kt"&gt;sample&lt;/a&gt; on how we can unit test our ViewModels with those changes in place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;As you can see, using kotlin Flows on the UI layer is still not always straightforward, but still, I prefer it over LiveData, to have access to all its APIs, and for a consistent API across all layers, for the issue we discussed here, I personally just put the explained logic in a BaseFragment/BaseViewModel, and then I can use it in all the screens without any boilerplate, and it worked well for me on my personal app since 2018.&lt;br&gt;
Let's hope that this &lt;a href="https://github.com/Kotlin/kotlinx.coroutines/issues/2223"&gt;feature request&lt;/a&gt; gets implemented to offer a way to pause the collection cooperatively without cancelling it, which would fix the issue completely.&lt;/p&gt;

&lt;p&gt;What do you think about the solutions explained on this article? And did I miss a simpler solution for this issue? Let me know on the comments.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>flow</category>
      <category>coroutines</category>
    </item>
  </channel>
</rss>
