<?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>DEV Community: Christophe Beyls</title>
    <description>The latest articles on DEV Community by Christophe Beyls (@cbeyls).</description>
    <link>https://dev.to/cbeyls</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1214397%2F05998be6-b42f-49fe-a85c-635a92363663.png</url>
      <title>DEV Community: Christophe Beyls</title>
      <link>https://dev.to/cbeyls</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cbeyls"/>
    <language>en</language>
    <item>
      <title>Strategies for automatically refreshing data on Android using Kotlin Flow</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Sat, 05 Aug 2023 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/strategies-for-automatically-refreshing-data-on-android-using-kotlin-flow-2de3</link>
      <guid>https://dev.to/cbeyls/strategies-for-automatically-refreshing-data-on-android-using-kotlin-flow-2de3</guid>
      <description>&lt;p&gt;This is the third part of a series of articles discussing the usage of Kotlin Flow to efficiently load data in Android applications. It’s a direct follow-up to part 2: &lt;a href="https://dev.to/cbeyls/smarter-shared-kotlin-flows-41n0"&gt;“Smarter Shared Kotlin Flows”&lt;/a&gt;, as it reuses the same concepts to cover another use case: automatic periodic refresh of the user interface.&lt;/p&gt;




&lt;h2&gt;
  
  
  Simple periodic refresh
&lt;/h2&gt;

&lt;p&gt;When it’s not possible to determine precisely when a data set displayed by the UI has changed, or when it changes too frequently, a common strategy is to reload the data periodically at a fixed interval while the screen is visible.&lt;/p&gt;

&lt;p&gt;One of the simplest ways to achieve this is to create a Flow from an infinite loop calling &lt;code&gt;delay()&lt;/code&gt; between emissions:&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;tickerFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Duration&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;Unit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&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;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;// Tick&lt;/span&gt;
        &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;period&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;This is equivalent to the &lt;a href="https://reactivex.io/documentation/operators/interval.html" rel="noopener noreferrer"&gt;&lt;code&gt;Observable.interval()&lt;/code&gt;&lt;/a&gt; operator in RxJava with a fixed emitted value (&lt;code&gt;Unit&lt;/code&gt;) and an initial delay of &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, transform this Flow using the &lt;code&gt;map()&lt;/code&gt; or &lt;code&gt;mapLatest()&lt;/code&gt; operator to perform the loading action on each “tick” of the timer and return the result:&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;tickerFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;REFRESH_INTERVAL&lt;/span&gt;&lt;span class="p"&gt;)&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;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadSomeData&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;Note the subtle difference in behavior between the two operators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/map.html" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;map()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; the entire Flow will be executed in sequence within a &lt;em&gt;single coroutine&lt;/em&gt;, meaning &lt;code&gt;delay()&lt;/code&gt; will only start running &lt;em&gt;after&lt;/em&gt; the loading operation completes. As a result, each loading operation will be delayed by the amount of time it took to perform the previous loading operation, plus the fixed interval.&lt;/li&gt;
&lt;li&gt;With &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/map-latest.html" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;mapLatest()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; the &lt;em&gt;main coroutine&lt;/em&gt; will collect the upstream values of &lt;code&gt;tickerFlow()&lt;/code&gt; while a &lt;em&gt;child coroutine&lt;/em&gt; will be created to perform the loading operation concurrently and collect the result without suspending the main coroutine. This means that &lt;code&gt;delay()&lt;/code&gt; will start running &lt;em&gt;immediately&lt;/em&gt; after the previous tick and each loading operation will start precisely according to schedule. This also means that the interval must be longer than the typical loading time because it will act as a &lt;strong&gt;timeout&lt;/strong&gt;: a previous loading operation that did not complete in time when &lt;code&gt;tickerFlow()&lt;/code&gt; emits a new value will be canceled. A new child coroutine then replaces the previous one to execute the next loading operation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This simple implementation will always trigger a new load immediately when the Flow collection starts or restarts, without taking the previous run into account. This is good enough for short intervals of a few seconds, when the loading action is considered cheap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making refresh smarter in order to leverage caching
&lt;/h2&gt;

&lt;p&gt;However, for longer refresh intervals and when the loading action demands more resources (like performing an API call), the above algorithm is not very efficient: when a screen that was temporarily hidden becomes visible again and the Flow collection restarts, &lt;strong&gt;we would like to avoid the unnecessary work of reloading data that is still considered fresh for the minutes or hours to come&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/cbeyls/kotlins-flow-in-viewmodels-its-complicated-livedata-is-still-your-friend-240c"&gt;In the first article&lt;/a&gt;, we saw that &lt;strong&gt;&lt;code&gt;StateFlow&lt;/code&gt;&lt;/strong&gt; is commonly used to cache the latest value of a Flow and share it between multiple subscribers. But StateFlow and SharedFlow have their limitations, as they are unable to simply pause and resume work following the Activity lifecycle: if the underlying Flow collection is stopped when the screen is hidden, it always has to restart from scratch when the screen becomes visible again, making the cache useless in that scenario.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/cbeyls/smarter-shared-kotlin-flows-41n0"&gt;In the second article&lt;/a&gt;, we studied the creation of a custom Flow operator designed to work around these limitations: &lt;strong&gt;&lt;code&gt;flowWhileShared()&lt;/code&gt;&lt;/strong&gt;. It allows to make only the upstream part of an underlying Flow lifecycle-aware, so that the heavy work in the downstream part of the Flow can be avoided when combined with some filtering logic. StateFlow’s cache can then be used to its full potential.&lt;/p&gt;

&lt;p&gt;As it turns out, we can use that same operator to implement a smarter version of &lt;code&gt;tickerFlow()&lt;/code&gt;, designed to be used in combination with &lt;code&gt;StateFlow&lt;/code&gt;. &lt;strong&gt;&lt;code&gt;synchronizedTickerFlow()&lt;/code&gt;&lt;/strong&gt; is lifecycle-aware and will only emit values while the parent StateFlow has at least one subscriber. What makes it smarter is that it also &lt;strong&gt;remembers the time when to emit next&lt;/strong&gt;, so after resuming from a pause with no subscribers, it will first wait until that time is reached before emitting the next value.&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;synchronizedTickerFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;subscriptionCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timeSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TimeSource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ElapsedRealTimeSource&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;Unit&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;flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;nextEmissionTimeMark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TimeMark&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="nf"&gt;flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;nextEmissionTimeMark&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;delay&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="nf"&gt;elapsedNow&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;while&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;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;nextEmissionTimeMark&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timeSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;markNow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;period&lt;/span&gt;
                &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;period&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="nf"&gt;flowWhileShared&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subscriptionCount&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collect&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s analyze the code in detail.&lt;/p&gt;

&lt;p&gt;One of the first things you’ll notice is that the time counting logic is based on the new &lt;code&gt;kotlin.time&lt;/code&gt; API that became stable in version 1.9.0 of the Kotlin standard library. This includes the classes &lt;code&gt;Duration&lt;/code&gt;, &lt;code&gt;TimeSource&lt;/code&gt; and &lt;code&gt;TimeMark&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The main Flow returned by the function collects the output of a secondary Flow used internally. The role of the main Flow is simply to &lt;strong&gt;encapsulate state&lt;/strong&gt; (&lt;code&gt;nextEmissionTimeMark&lt;/code&gt;) and make it local to each collection, as it is the case with all Flow operators. The secondary Flow is the one that &lt;strong&gt;starts and stops according to the parent lifecycle&lt;/strong&gt; (stopping immediately when the provided &lt;code&gt;subscriptionCount&lt;/code&gt; reaches zero) thanks to the &lt;code&gt;flowWhileShared()&lt;/code&gt; operator.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; we don’t pass any timeout value to the sharing strategy &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-sharing-started/-companion/-while-subscribed.html" rel="noopener noreferrer"&gt;&lt;code&gt;SharingStarted.WhileSubscribed()&lt;/code&gt;&lt;/a&gt; because the cost of stopping and restarting the secondary Flow is cheap.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main logic of that secondary flow is almost identical to &lt;code&gt;tickerFlow()&lt;/code&gt;, the only difference being that the first “tick” will only be emitted when &lt;code&gt;nextEmissionTimeMark&lt;/code&gt; is reached. A &lt;code&gt;TimeMark&lt;/code&gt; represents a point in time and &lt;code&gt;nextEmissionTimeMark&lt;/code&gt; is the earliest point in time when the next emission needs to occur.&lt;/p&gt;

&lt;p&gt;When the main Flow collection starts, &lt;code&gt;nextEmissionTimeMark&lt;/code&gt; is initially &lt;code&gt;null&lt;/code&gt; and the first tick is emitted immediately with no delay. Then, after each emission, the &lt;em&gt;future&lt;/em&gt; point in time of the next emission is computed by retrieving the &lt;em&gt;current&lt;/em&gt; point in time from a &lt;code&gt;TimeSource&lt;/code&gt; using &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.time/-time-source/mark-now.html" rel="noopener noreferrer"&gt;&lt;code&gt;markNow()&lt;/code&gt;&lt;/a&gt; and adding the &lt;code&gt;period&lt;/code&gt; &lt;code&gt;Duration&lt;/code&gt; to it.&lt;/p&gt;

&lt;p&gt;When the secondary Flow restarts after a pause and &lt;code&gt;nextEmissionTimeMark&lt;/code&gt; is not &lt;code&gt;null&lt;/code&gt;, the amount of time (&lt;code&gt;Duration&lt;/code&gt;) to wait to reach that point in time is computed by calling &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.time/-time-mark/elapsed-now.html" rel="noopener noreferrer"&gt;&lt;code&gt;elapsedNow()&lt;/code&gt;&lt;/a&gt; on the &lt;code&gt;TimeMark&lt;/code&gt; and &lt;em&gt;negating&lt;/em&gt; the result, because &lt;code&gt;elapsedNow()&lt;/code&gt; actually returns the elapsed time between the &lt;code&gt;TimeMark&lt;/code&gt; and now, which is a negative value if the &lt;code&gt;TimeMark&lt;/code&gt; is in the future. Note that calling &lt;code&gt;delay()&lt;/code&gt; with a negative &lt;code&gt;Duration&lt;/code&gt; has no effect and will return immediately, so we don’t need to separately handle the case where the next emission time has already been reached and is now in the past.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foxpfyqaht867r5zlfg9c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foxpfyqaht867r5zlfg9c.jpg" alt="Roy from " width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The importance of using the right &lt;code&gt;TimeSource&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For this code to work properly, it’s mandatory to use a &lt;code&gt;TimeSource&lt;/code&gt; based on a &lt;strong&gt;monotonic&lt;/strong&gt; clock instead of a wall clock. A monotonic clock is a clock that always moves forward and cannot be adjusted or reset. &lt;code&gt;kotlin.time&lt;/code&gt; already provides &lt;code&gt;TimeSource.Monotonic&lt;/code&gt; for this purpose, which is based on &lt;code&gt;System.nanoTime()&lt;/code&gt; on the JVM and Android. While this clock is good enough for the JVM, it can cause issues for Android applications because it stops when the device’s CPU enters deep sleep, which can occur after the screen turns off. This means that if a user unlocks an Android device that just spent 10 minutes in deep sleep and goes back to the application, the data refresh will be triggered 10 minutes too late.&lt;/p&gt;

&lt;p&gt;On Android, a more suitable clock for this usage is &lt;code&gt;SystemClock.elapsedRealtimeNanos()&lt;/code&gt; which is a monotonic clock with nanosecond precision that includes the time that the device spent in deep sleep mode. Since the official Android Jetpack libraries for Kotlin don’t (yet?) provide a &lt;code&gt;TimeSource&lt;/code&gt; based on this clock, we create our own:&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;object&lt;/span&gt; &lt;span class="nc"&gt;ElapsedRealTimeSource&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AbstractLongTimeSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DurationUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NANOSECONDS&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;read&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SystemClock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elapsedRealtimeNanos&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;toString&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"TimeSource(SystemClock.elapsedRealtimeNanos())"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the &lt;code&gt;TimeSource&lt;/code&gt; is passed as argument to &lt;code&gt;synchronizedTickerFlow()&lt;/code&gt;, the implementation can be swapped easily, for example by using &lt;code&gt;TestTimeSource&lt;/code&gt; for tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;

&lt;p&gt;Following is an example of how &lt;code&gt;synchronizedTickerFlow()&lt;/code&gt; can be used in combination with the &lt;code&gt;stateFlow()&lt;/code&gt; factory function described in the &lt;a href="https://dev.to/cbeyls/smarter-shared-kotlin-flows-41n0"&gt;previous article&lt;/a&gt;. As a reminder, this factory function allows a &lt;code&gt;StateFlow&lt;/code&gt; to share its &lt;code&gt;subscriptionCount&lt;/code&gt; with the underlying Flow that feeds it.&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;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stateFlow&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="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;subscriptionCount&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;synchronizedTickerFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;REFRESH_PERIOD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subscriptionCount&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;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadSomeData&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;Here is how this code reacts to the changes of UI state, step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the UI first becomes visible and starts collecting the &lt;code&gt;results&lt;/code&gt; StateFlow, &lt;code&gt;synchronizedTickerFlow()&lt;/code&gt; will start emitting new values periodically, which will trigger loading the latest data. This data will be cached in the StateFlow and shared with all current and future subscribers;&lt;/li&gt;
&lt;li&gt;When the UI becomes invisible and stops collecting the StateFlow, the underlying Flow stays active but the ticker will not emit any new value so no new data will be loaded. We are saving resources;&lt;/li&gt;
&lt;li&gt;When the UI becomes visible again and starts collecting again, it will immediately receive the cached value of the StateFlow. In the underlying Flow, the ticker will resume. But first it will wait for the planned time of the next emission to be reached before emitting anything. This way, data will be preserved in the StateFlow cache as long as it’s valid instead of being replaced unconditionally. We are now saving more resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Advanced use case: sharing the time reference
&lt;/h3&gt;

&lt;p&gt;Sometimes, a screen requires multiple data sources to be queried separately, and updated periodically. &lt;strong&gt;If the data is time-dependent&lt;/strong&gt;, all the sources need to use the same point in time as a reference to ensure their results are consistent with each other.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Example: you want to periodically load both the schedule of the last 10 minutes and the schedule of the next 10 minutes and make sure the results don’t overlap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That reference point in time can be updated periodically using &lt;code&gt;synchronizedTickerFlow()&lt;/code&gt; and cached and shared using &lt;code&gt;stateFlow()&lt;/code&gt;, exactly like in the previous example:&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;timeReferenceFlow&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;Instant&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stateFlow&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="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="n"&gt;subscriptionCount&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;synchronizedTickerFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;REFRESH_PERIOD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subscriptionCount&lt;/span&gt;&lt;span class="p"&gt;)&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="nc"&gt;Instant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;filterNotNull&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What’s different is that &lt;strong&gt;each data source will connect to the same &lt;code&gt;timeReferenceFlow&lt;/code&gt; instance&lt;/strong&gt; and use a combination of &lt;code&gt;flowWhileShared()&lt;/code&gt; and &lt;code&gt;distinctUntilChanged()&lt;/code&gt; to ensure the data is only updated when the time reference changes. The result will also be cached in a StateFlow:&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;results1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stateFlow&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="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;subscriptionCount&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;timeReferenceFlow&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flowWhileShared&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subscriptionCount&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="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;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;timeReference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadDataForTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeReference&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;Having a StateFlow depend on another one using this pattern allows the UI lifecycle to be propagated and aggregated from one StateFlow to the next through the &lt;code&gt;subscriptionCount&lt;/code&gt;. Here is how they will react to the changes of UI state:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the UI starts collecting the first result StateFlow, its &lt;code&gt;subscriptionCount&lt;/code&gt; will update from 0 to 1 and &lt;code&gt;flowWhileShared()&lt;/code&gt; will start collecting the upstream &lt;code&gt;timeReferenceFlow&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Being a StateFlow itself, the &lt;code&gt;subscriptionCount&lt;/code&gt; of &lt;code&gt;timeReferenceFlow&lt;/code&gt; will also update from 0 to 1 and &lt;code&gt;synchronizedTickerFlow()&lt;/code&gt; will wake up and start emitting new values as soon as the previous one is expired;&lt;/li&gt;
&lt;li&gt;As more result StateFlows start collecting the same &lt;code&gt;timeReferenceFlow&lt;/code&gt;, they all increment its &lt;code&gt;subscriptionCount&lt;/code&gt; and receive the cached time reference immediately. The timer stays active and each newly computed time reference is distributed to all subscribers;&lt;/li&gt;
&lt;li&gt;When all the result StateFlows connected to &lt;code&gt;timeReferenceFlow&lt;/code&gt; stop being collected by the UI, its &lt;code&gt;subscriptionCount&lt;/code&gt; will finally reach zero and &lt;code&gt;synchronizedTickerFlow()&lt;/code&gt; will stop emitting new values.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We have demonstrated that &lt;code&gt;timeReferenceFlow&lt;/code&gt; is also lifecycle-aware, even if it’s never collected directly by the UI. Its value will only update if it has at least one active subscriber &lt;strong&gt;and&lt;/strong&gt; the previous value has expired. This allows maximizing cache usage throughout the application while keeping all the results consistent with each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Using a ticker Flow is a simple and elegant way to periodically update data presented to the user in Kotlin applications. In order to implement efficient caching on Android, it’s possible to synchronize the timer with the UI lifecycle by stopping it when a StateFlow exposing the data has no more subscribers, and by memorizing the time of the next tick according to the proper monotonic clock.&lt;/p&gt;

&lt;p&gt;That complexity can be hidden behind a few reusable Flow operators.&lt;/p&gt;




&lt;p&gt;I’ve been using this technique successfully in production applications. Do you think it makes sense or is it too complex? Did you find a better way to achieve the same results? Please share your feedback in the comments section and help spread the word if you liked it.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>flow</category>
      <category>android</category>
      <category>androiddev</category>
    </item>
    <item>
      <title>Kotlin JSON Benchmark on Android (2022): Moshi vs Kotlin Serialization</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Thu, 13 Oct 2022 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/kotlin-json-benchmark-on-android-2022-moshi-vs-kotlin-serialization-3g9j</link>
      <guid>https://dev.to/cbeyls/kotlin-json-benchmark-on-android-2022-moshi-vs-kotlin-serialization-3g9j</guid>
      <description>&lt;p&gt;When it comes to automatic serialization and deserialization of Kotlin classes using the JSON format, the two main libraries compatible with Kotlin metadata are currently &lt;em&gt;Moshi&lt;/em&gt; and &lt;em&gt;Kotlin Serialization&lt;/em&gt;. This compatibility is especially important for &lt;strong&gt;non-null types&lt;/strong&gt; and &lt;strong&gt;default values&lt;/strong&gt; during deserialization, where lack of proper Kotlin support could result in unexpected values occurring at runtime, such as null values in non-null fields. If you’re still using legacy libraries like Gson to parse Kotlin classes, it’s time to reconsider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Moshi&lt;/strong&gt; has been supporting Kotlin classes since version 1.5.0, released in 2017. One year later, the next major release 1.6.0 added an annotation processor to generate adapters for Kotlin classes at compile time. I was quite interested in the performance gains allowed by this solution and &lt;a href="https://dev.to/cbeyls/advanced-json-parsing-techniques-using-moshi-and-kotlin-256h"&gt;wrote an article&lt;/a&gt; detailing what the generated code does.&lt;/p&gt;

&lt;p&gt;JetBrains released version 1.0.0 of &lt;strong&gt;Kotlin Serialization&lt;/strong&gt; in 2020 with built-in support for JSON. This library generates adapters at compile time similarly to Moshi’s annotation processor while being compatible with more platforms and formats. The lack of initial support for streaming was disappointing, so I didn’t even consider using it in production until streaming support was eventually added in version 1.3.0 in 2021. The JSON engine had also been rewritten in the meantime in order to improve performance. Recently, version 1.4.0 added integration with the Okio library, the same library used by Moshi under the hood.&lt;/p&gt;

&lt;p&gt;Now that Kotlin Serialization looks full-featured and well-optimized, I thought it would be a good time to compare its performance against Moshi on Android devices with some benchmarks. &lt;strong&gt;Which one is the fastest? Take your bets.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The contenders
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/square/moshi#reflection" rel="noopener noreferrer"&gt;Moshi-Kotlin Reflection&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The runtime Kotlin plugin of the Moshi library. The JSON adapters are generated at runtime using reflection. The main downside of this library is that it adds a runtime dependency to the big &lt;code&gt;kotlin-reflect&lt;/code&gt; library (currently a 3 MiB jar file).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/square/moshi#codegen" rel="noopener noreferrer"&gt;Moshi-Kotlin Codegen&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The annotation processor Kotlin plugin of the Moshi library. The JSON adapters are generated at compile time by an annotation processor (compatible with both &lt;code&gt;kapt&lt;/code&gt; and &lt;code&gt;KSP&lt;/code&gt;). It increases build times, but adds no extra runtime dependency (besides the generated adapters).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/ZacSweers/MoshiX/tree/main/moshi-ir" rel="noopener noreferrer"&gt;Moshi-IR&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;An alternative Kotlin IR implementation of Moshi Codegen, created by Zac Sweers (the current main maintainer of Moshi). It does the exact same thing as Moshi-Kotlin Codegen, but is implemented as a Kotlin compiler plugin instead of an annotation processor for faster build times.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Unlike Moshi-Kotlin Codegen, Moshi-IR doesn’t use very limited reflection at runtime to &lt;strong&gt;read default parameter values&lt;/strong&gt;.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;But since the Kotlin model classes used in the following benchmarks don’t have any default parameter values, &lt;strong&gt;this optimization will not be put to the test&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/Kotlin/kotlinx.serialization" rel="noopener noreferrer"&gt;Kotlin Serialization&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The official Kotlin multiplatform / multi-format serialization library created and maintained by JetBrains. The JSON adapters are generated at compile time by a compiler plugin. Contrary to Moshi which is only compatible with the JSON format, the adapters generated by Kotlin Serialization support other formats: Protocol Buffers, CBOR, HOCON and Properties. Support for more formats is also provided by third-party plugins. &lt;em&gt;The benchmarks in this article will only test the JSON format.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark setup
&lt;/h2&gt;

&lt;p&gt;This benchmark is based on Zac Sweers’ &lt;a href="https://github.com/ZacSweers/json-serialization-benchmarking" rel="noopener noreferrer"&gt;JSON Serialization Benchmarking&lt;/a&gt; github project, updated to add new tests and support the most recent versions of the libraries. You can also &lt;a href="https://github.com/cbeyls/json-serialization-benchmarking" rel="noopener noreferrer"&gt;find it on Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Two different tests are run for each library, in both reading an writing modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encoding and decoding Kotlin data classes to and from &lt;strong&gt;a JSON String&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Encoding and decoding Kotlin data classes to and from &lt;strong&gt;an in-memory byte buffer&lt;/strong&gt; containing JSON data encoded in UTF-8. This recreates the conditions of reading or writing JSON files or JSON network responses, without the cost of I/O.
&lt;em&gt;Kotlin Serialization supports 2 different APIs to do this: &lt;strong&gt;&lt;code&gt;java.io&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;okio&lt;/code&gt;&lt;/strong&gt;. Both will be tested.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benchmarks are run using the &lt;a href="https://developer.android.com/jetpack/androidx/releases/benchmark" rel="noopener noreferrer"&gt;AndroidX Benchmark&lt;/a&gt; (Microbenchmark) library for more accuracy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test data
&lt;/h3&gt;

&lt;p&gt;The test data consists of a 230 KiB JSON file encoded in UTF-8 containing a list of 60 users. Each user contains 23 fields of various types, including nested objects and nested lists. For reference, here is the Kotlin data class definition:&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;data class&lt;/span&gt; &lt;span class="nc"&gt;User&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&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;guid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&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;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;pictureUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Name&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;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;about&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;registered&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;latitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&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;longitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&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;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&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;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&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;friends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Friend&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;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&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;greeting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;favoriteFruit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;eyeColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same data is used for read and write tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Libraries versions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;AndroidX Benchmark &lt;strong&gt;1.1.0&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Kotlin &lt;strong&gt;1.7.10&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Okio &lt;strong&gt;3.2.0&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Moshi &lt;strong&gt;1.14.0&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;MoshiX (Moshi-IR) &lt;strong&gt;0.18.3&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Kotlin Serialization (KSerizalizer) &lt;strong&gt;1.4.0&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test hardware and operating system
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Google Pixel 4a (2020) running Android 13&lt;/li&gt;
&lt;li&gt;Google Nexus 5 (2013) running Android 6&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Write performance
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvo0lscpcr9m3uz0q8iz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvo0lscpcr9m3uz0q8iz.png" alt="Write performance - Pixel 4a (Android 13)" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqbynlbpf5tjobn9l4hwk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqbynlbpf5tjobn9l4hwk.png" alt="Write performance - Nexus 5 (Android 6)" width="799" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; the scale on the Nexus 5 graph is about 10x the scale of the Pixel 4a graph, meaning the tests ran about 10 times slower on this older device.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first thing we can notice is that the &lt;strong&gt;reflection-based adapters are much slower&lt;/strong&gt; than the compile-time generated adapters, especially on the older Android version.&lt;/p&gt;

&lt;p&gt;We can verify that performance of Moshi-Kotlin Codegen and Moshi-IR is virtually identical, since the generated code is supposed to be the same.&lt;/p&gt;

&lt;p&gt;The Moshi tests producing a String run a bit &lt;strong&gt;slower&lt;/strong&gt; than the tests writing to a byte buffer. This can be explained by the way this library works:&lt;/p&gt;

&lt;p&gt;Moshi is built on top of the &lt;a href="https://github.com/lysine-dev/okio" rel="noopener noreferrer"&gt;&lt;strong&gt;Okio&lt;/strong&gt;&lt;/a&gt; library and works primarily with &lt;strong&gt;byte buffers&lt;/strong&gt;, not characters or Strings. Obtaining a String requires an extra step: reading back and decoding the entire byte buffer into a String. That extra step is the overhead that can be seen in the Moshi String benchmarks. It’s less visible on the slower Nexus 5 because producing the bytes takes much more time.&lt;/p&gt;

&lt;p&gt;In comparison, the Kotlin Serialization tests producing a String run &lt;strong&gt;faster&lt;/strong&gt; than the tests writing to a byte buffer. This can again be explained by the way this library works:&lt;/p&gt;

&lt;p&gt;The JSON module of Kotlin Serialization works primarily with &lt;strong&gt;sequences of characters&lt;/strong&gt; and Strings. Writing to a byte buffer requires an extra step: converting the characters to bytes. This conversion is performed either by the &lt;strong&gt;&lt;code&gt;java.io.Writer class&lt;/code&gt;&lt;/strong&gt; (used by &lt;code&gt;Json.encodeToStream()&lt;/code&gt; in the &lt;code&gt;buffer&lt;/code&gt; test) or the &lt;strong&gt;&lt;code&gt;okio.BufferedSink&lt;/code&gt;&lt;/strong&gt; class (used by &lt;code&gt;Json.encodeToBufferedSink()&lt;/code&gt; in the &lt;code&gt;okiobuffer&lt;/code&gt; test). We can see that the performance of these two methods is very close so which one to use doesn’t really matter.&lt;/p&gt;

&lt;p&gt;In both cases, writing to byte buffers on the lower-end Nexus 5 is more than &lt;strong&gt;two times slower&lt;/strong&gt; using Kotlin Serialization JSON compared to using Moshi. On the newer Pixel 4a, the performance of the two libraries is very close. This could be partially explained by the fact that Kotlin Serialization JSON allocated two times more objects than Moshi during the test (1373 allocations vs 769 for Moshi), and the memory allocation and garbage collector performance improved significantly in newer Android versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner:&lt;/strong&gt; Moshi-IR / Moshi-Kotlin Codegen, even if Kotlin Serialization is close on newer devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loser:&lt;/strong&gt; Moshi-Kotlin Reflection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read performance
&lt;/h2&gt;

&lt;p&gt;Now let’s test the more common operation of converting JSON data to Kotlin objects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxk6gii2ijrl5nxe5pfx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxk6gii2ijrl5nxe5pfx1.png" alt="Read performance - Pixel 4a (Android 13)" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flzbt44do20unm0ttbgyr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flzbt44do20unm0ttbgyr.png" alt="Read performance - Nexus 5 (Android 6)" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On average, the reading tests are almost two times slower than the writing tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reflection-based Moshi adapters are still slower&lt;/strong&gt; than the compile-time generated adapters, but this time the overhead is lower than for writing tests.&lt;/p&gt;

&lt;p&gt;The performance of Moshi-Kotlin Codegen and Moshi-IR is still virtually identical as expected.&lt;/p&gt;

&lt;p&gt;Again, the Moshi tests taking a String as input run a bit slower than the tests reading directly from a byte buffer for a similar reason: Moshi needs to encode the String to a byte buffer first.&lt;/p&gt;

&lt;p&gt;The most important outtake from this chart is that &lt;strong&gt;the buffering performance of Moshi-Kotlin Codegen/Moshi-IR is on par with Kotlin Serialization Json&lt;/strong&gt;. The teams at JetBrains did an impressive job at improving performance since version 1.0.0 of the library, while also adding buffering support. It’s still a bit slower on the Nexus 5, probably because of the lower byte-to-char decoding performance of &lt;code&gt;java.io.Reader&lt;/code&gt; compared to Okio on older Android versions.&lt;/p&gt;

&lt;p&gt;Last but not least, we need to talk about the elephant in the room (the last bar on the right): &lt;strong&gt;there is something really wrong with the reading performance of the new Okio module of Kotlin Serialization JSON&lt;/strong&gt;. While it’s supposed to reduce overhead, it’s actually &lt;strong&gt;two times slower&lt;/strong&gt; than the “regular” streaming API based on &lt;code&gt;java.io.InputStream&lt;/code&gt; and &lt;code&gt;java.io.Reader&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The reason for this huge performance gap becomes obvious when looking at the source code of the current implementation:&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;internal&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OkioSerialReader&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;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BufferedSource&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;SerialReader&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;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CharArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bufferOffset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&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="nf"&gt;exhausted&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bufferOffset&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&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="nf"&gt;readUtf8CodePoint&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toChar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&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;i&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;else&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sure enough, the character array buffer is filled by &lt;strong&gt;decoding one character at a time&lt;/strong&gt;, and checking for buffer exhaustion after each character. This is definitely a performance bottleneck, but an understandable one since the Okio API doesn’t provide a way to decode UTF-8 characters in batch to a &lt;code&gt;CharArray&lt;/code&gt; yet. The best it can do is return a new &lt;code&gt;String&lt;/code&gt; to copy to the array, which would allocate memory but probably still be faster.&lt;/p&gt;

&lt;p&gt;In its current state, I see &lt;strong&gt;no reason to use the new Okio APIs of Kotlin Serialization JSON when targeting Android or the JVM&lt;/strong&gt;. Just create a regular &lt;code&gt;java.io.InputStream&lt;/code&gt; from your &lt;code&gt;okio.BufferedSource&lt;/code&gt; instead:&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="nc"&gt;Json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decodeFromStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bufferedSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inputStream&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That being said, if you need to implement a &lt;strong&gt;multiplatform JSON streaming parser&lt;/strong&gt; that works on other platforms, then the Okio API of Kotlin Serialization is the only option. If the payload is small, it's probably better to fully convert it to a &lt;code&gt;String&lt;/code&gt; first and not use streaming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner:&lt;/strong&gt; Moshi-IR / Moshi-Kotlin Codegen and Kotlin Serialization using &lt;code&gt;InputStream&lt;/code&gt; (tie).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loser:&lt;/strong&gt; Kotlin Serialization using &lt;code&gt;BufferedSource&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read performance — Selective
&lt;/h2&gt;

&lt;p&gt;In this final test, we’ll measure the performance of &lt;strong&gt;partial decoding&lt;/strong&gt;: sometimes we’re not interested in parsing the entire JSON file and fields can be skipped. To test this, we modify the &lt;code&gt;User&lt;/code&gt; data class to keep only 5 fields on 23:&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;data class&lt;/span&gt; &lt;span class="nc"&gt;User&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&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;guid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Name&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test JSON file remains unchanged. All fields not present in the &lt;code&gt;User&lt;/code&gt; class will be skipped by the JSON adapters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd27jzppgig1i979k9p3p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd27jzppgig1i979k9p3p.png" alt="Read performance - Selective - Pixel 4a (Android 13)" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwelyiilvo99yg41dt7di.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwelyiilvo99yg41dt7di.png" alt="Read performance - Selective - Nexus 5 (Android 6)" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous test, the buffered reading performance of Moshi and Kotlin Serialization was identical or very close. With partial decoding, we can see that the gap widens and &lt;strong&gt;Moshi is ahead of Kotlin Serialization JSON&lt;/strong&gt;, especially on &lt;strong&gt;older devices&lt;/strong&gt; where it’s almost &lt;strong&gt;twice as fast&lt;/strong&gt; when decoding bytes in streaming.&lt;/p&gt;

&lt;p&gt;This is probably due to the fact that Moshi is able to &lt;strong&gt;directly skip unwanted bytes&lt;/strong&gt; in the stream without having to decode them to characters first or allocate any memory, thanks to the powerful API of the Okio library. Kotlin Serialization JSON, on the other hand, has to decode all bytes to characters and also performs memory allocations while skipping the unwanted fields.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;As with any microbenchmark, one needs to be careful when it comes to drawing conclusions. That being said, it’s safe to claim that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The performance of Moshi 1.14.0 and Kotlin Serialization JSON 1.4.0 is very close&lt;/strong&gt; and they both perfom very well;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moshi-Kotlin Reflection should be avoided&lt;/strong&gt; because compile-time generated adapters are always faster and don’t require extra runtime dependencies;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The current Okio integration in Kotlin Serialization JSON is mediocre&lt;/strong&gt; and I would advise not to use it on Android and the JVM. It provides no substantial performance gains for encoding and hurts performance for decoding. I suspect that either this integration will be phased out in a future release, or the core JSON engine will be rewritten to take real advantage of Okio (like Moshi) instead of the limited high-level integration we have now.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the most important conclusion of all:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The time required to encode or decode the JSON data is so small&lt;/strong&gt; compared to the latency of the network or storage access that it doesn’t really matter and won’t be noticed, unless it’s so bad it goes off the charts. This is not the case for these two libraries.&lt;/p&gt;

&lt;p&gt;Which one should you pick? The one that fits your needs best.&lt;br&gt;
Both have their qualities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moshi has more advanced features and provides a lower-level JSON API for maximum control;&lt;/li&gt;
&lt;li&gt;Kotlin Serialization is multiplatform (Javascript, Kotlin native) and its adapters work with other formats than JSON without extra configuration in the model classes. It’s also compatible with &lt;em&gt;unsigned integer types&lt;/em&gt;, &lt;em&gt;value classes&lt;/em&gt; and &lt;em&gt;sealed classes&lt;/em&gt; out-of-the-box which is something to consider.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Thank you for reading and please share your own benchmark results if you have some.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>json</category>
      <category>moshi</category>
    </item>
    <item>
      <title>ViewLifecycleLazy and other ways to avoid View memory leaks in Android Fragments</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Tue, 27 Sep 2022 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/viewlifecyclelazy-and-other-ways-to-avoid-view-memory-leaks-in-android-fragments-ao4</link>
      <guid>https://dev.to/cbeyls/viewlifecyclelazy-and-other-ways-to-avoid-view-memory-leaks-in-android-fragments-ao4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffns2dgugom17dx22kn6q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffns2dgugom17dx22kn6q.jpg" alt="A leaking pipe" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;
Are your Fragments leaking?



&lt;p&gt;Handling the lifecycle of Android Fragments is difficult. I already covered this topic in &lt;a href="https://dev.to/cbeyls/architecture-components-pitfalls-livedata-and-the-fragment-lifecycle-1da0"&gt;an article I wrote in 2017&lt;/a&gt;, before Google added &lt;a href="https://developer.android.com/reference/androidx/fragment/app/Fragment#getViewLifecycleOwner()" rel="noopener noreferrer"&gt;a View-specific &lt;code&gt;Lifecycle&lt;/code&gt;&lt;/a&gt; to Fragments in an attempt to solve some issues.&lt;/p&gt;

&lt;p&gt;Until now, the number one cause of memory leaks when using Fragments remains the same: not properly clearing all direct and indirect View references in &lt;code&gt;onDestroyView()&lt;/code&gt;. Tools like &lt;a href="https://square.github.io/leakcanary/" rel="noopener noreferrer"&gt;LeakCanary&lt;/a&gt; can help detecting some of these cases.&lt;/p&gt;

&lt;p&gt;And of course, &lt;strong&gt;Jetpack Compose&lt;/strong&gt; represents a big paradigm change which completely removes the need to keep View references but hey, we still have our legacy codebases to maintain!&lt;/p&gt;




&lt;p&gt;I recently came across &lt;a href="https://itnext.io/an-update-to-the-fragmentviewbindingdelegate-the-bug-weve-inherited-from-autoclearedvalue-7fc0a89fcae1" rel="noopener noreferrer"&gt;a blog post from Gabor Varadi&lt;/a&gt; describing an issue he encountered with a custom Kotlin delegated property he created to simplify managing view bindings in Fragments.&lt;/p&gt;

&lt;p&gt;His solution is based on a class named &lt;a href="https://github.com/android/architecture-components-samples/blob/7466ae2015bb9bd9cf2c435a350070b29d71fd2b/GithubBrowserSample/app/src/main/java/com/android/example/github/util/AutoClearedValue.kt" rel="noopener noreferrer"&gt;&lt;code&gt;AutoClearedValue&lt;/code&gt;&lt;/a&gt; from the architecture components samples. &lt;strong&gt;The purpose of &lt;code&gt;AutoClearedValue&lt;/code&gt; is to provide a delegate that will automatically clear a value tied to one or more Views when the Fragment View hierarchy gets destroyed&lt;/strong&gt;, in order to avoid the aforementioned memory leaks. This is an elegant alternative to declaring a Fragment property as nullable and manually setting it to null in &lt;code&gt;onDestroyView()&lt;/code&gt;, which can be easily forgotten.&lt;/p&gt;

&lt;p&gt;It turns out I had already come up with my own solution to do the exact same thing. And since my version is simpler and generates more optimized bytecode compared to &lt;code&gt;AutoClearedValue&lt;/code&gt; and what Mr Varadi published, I decided to share it with you.&lt;/p&gt;




&lt;p&gt;I named this delegate &lt;code&gt;ViewLifecycleLazy&lt;/code&gt;. Like the name implies, the delegated property value is computed &lt;em&gt;lazily&lt;/em&gt; and the Fragment’s current view lifecycle is observed in order to automatically clear the value when it moves to the &lt;code&gt;DESTROYED&lt;/code&gt; state.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is how it’s used in Fragments, for example with View Binding:&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;MyFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;my_fragment&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;binding&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;viewLifecycleLazy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyFragmentBinding&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bind&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;h2&gt;
  
  
  Why it’s simpler
&lt;/h2&gt;

&lt;p&gt;The original code adds some unnecessary complexity by observing &lt;code&gt;viewLifecycleOwnerLiveData&lt;/code&gt;, then in turn registering a new lifecycle observer on the new &lt;code&gt;viewLifecycleOwner&lt;/code&gt; when it becomes available. &lt;strong&gt;It turns out this is not needed&lt;/strong&gt; because the &lt;code&gt;viewLifecycleOwner&lt;/code&gt; lifecycle observer can just be registered lazily, at the same time the value is initialized.&lt;/p&gt;

&lt;p&gt;Since the property is designed to be read &lt;strong&gt;only when a view hierarchy is available&lt;/strong&gt;, attempting to read it too early or too late will automatically throw an &lt;code&gt;IllegalStateException&lt;/code&gt; when calling &lt;code&gt;Fragment.requireView()&lt;/code&gt; or &lt;code&gt;Fragment.viewLifecycleOwner&lt;/code&gt;: we don’t need to do that check ourselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it generates more optimized bytecode
&lt;/h2&gt;

&lt;p&gt;The original code is a classic property delegate, an object implementing the &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.properties/-read-only-property/" rel="noopener noreferrer"&gt;&lt;code&gt;ReadOnlyProperty&lt;/code&gt;&lt;/a&gt; interface which includes this function:&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;abstract&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thisRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;KProperty&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;):&lt;/span&gt; &lt;span class="nc"&gt;V&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a result, the compiler needs to generate extra metadata in the form of &lt;strong&gt;one &lt;code&gt;KProperty&lt;/code&gt; object for each delegated property&lt;/strong&gt;, even if this parameter is not actually used in the code of the delegate. For more details, check my 2017 blog post &lt;a href="https://dev.to/cbeyls/exploring-kotlins-hidden-costs-part-3-delegated-properties-and-ranges-4obl"&gt;“Exploring Kotlin’s hidden costs — Part 3”&lt;/a&gt; which covers delegated properties.&lt;/p&gt;

&lt;p&gt;Kotlin 1.4 added &lt;a href="https://blog.jetbrains.com/kotlin/2019/12/what-to-expect-in-kotlin-1-4-and-beyond/#Optimized_delegated_properties_delegated-properties" rel="noopener noreferrer"&gt;an optimization allowing to skip the generation of this metadata&lt;/a&gt; for delegated property operators declared as &lt;strong&gt;&lt;code&gt;inline&lt;/code&gt;&lt;/strong&gt; and not using the &lt;code&gt;KProperty&lt;/code&gt; parameter. This includes the built-in operator of the standard &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-lazy/" rel="noopener noreferrer"&gt;&lt;code&gt;Lazy&lt;/code&gt;&lt;/a&gt; interface:&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;inline&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&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;Lazy&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;getValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thisRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;KProperty&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;):&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By implementing &lt;code&gt;Lazy&lt;/code&gt; instead of &lt;code&gt;ReadOnlyProperty&lt;/code&gt;, no unnecessary metadata code will be generated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; some may argue that this implementation does not strictly comply with the &lt;code&gt;Lazy&lt;/code&gt; contract which states that once initialized, a property must stay initialized. If you think this is problematic, it’s possible to alter the above code to not implement &lt;code&gt;Lazy&lt;/code&gt; and still benefit from the compiler optimization by adding a specialized inline delegated property operator for the &lt;code&gt;ViewLifecycleLazy&lt;/code&gt; class. The operator will have to be imported for &lt;code&gt;ViewLifecycleLazy&lt;/code&gt; to be recognized as a delegate.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final advice: only use it if you have to
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4xjqxsv0vj6placo42gb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4xjqxsv0vj6placo42gb.jpg" alt="The " width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should always try to architect your code in such a way that you don’t have to create properties in your Fragments to store references to Views in the first place.&lt;/p&gt;

&lt;p&gt;The best way to do this is to always pass View references as function arguments instead of retrieving them through the Fragment, and register lifecycle-aware callbacks in &lt;code&gt;onViewCreated()&lt;/code&gt; to update the View.&lt;br&gt;
For example:&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;MyFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fragment_example&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;myViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyViewModel&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;viewModels&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;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&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;viewHolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewHolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;initNavigationView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;navigationView&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;adapter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyAdapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;viewHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recyclerView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;adapter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adapter&lt;/span&gt;
        &lt;span class="n"&gt;myViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&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="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;viewHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleTextView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;
            &lt;span class="n"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&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="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;initNavigationView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;navigationView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;NavigationView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// TODO&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;As you can see in the above code, all view references like &lt;code&gt;viewHolder&lt;/code&gt; or &lt;code&gt;adapter&lt;/code&gt; are declared and used within the scope of the &lt;code&gt;onViewCreated()&lt;/code&gt; function so none have to be stored as properties in the Fragment.&lt;/p&gt;

&lt;p&gt;In order to improve readability, the code that configures the navigation menu is isolated in its own function &lt;code&gt;initNavigationView()&lt;/code&gt; and the view references are passed as arguments.&lt;/p&gt;

&lt;p&gt;Finally, the code which updates the View after its initialization is located inside a lifecycle-aware callback declared in &lt;code&gt;onViewCreated()&lt;/code&gt;, in this case in the form of a &lt;strong&gt;&lt;code&gt;LiveData&lt;/code&gt; observer&lt;/strong&gt;. It could also be a &lt;strong&gt;coroutine launched from a &lt;code&gt;LifecycleScope&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are rare cases where this technique can’t be used or would make the code too complex. For these cases, you can use &lt;strong&gt;&lt;code&gt;ViewLifecycleLazy&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s conclude with an example from one of my own projects:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;RecycledViewPoolProvider&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;recycledViewPool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecyclerView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RecycledViewPool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ParentFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fragment_parent&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;RecycledViewPoolProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;recycledViewPool&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;viewLifecycleLazy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;RecyclerView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RecycledViewPool&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;It illustrates how to share a single lazily-created &lt;a href="https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.RecycledViewPool" rel="noopener noreferrer"&gt;&lt;code&gt;RecycledViewPool&lt;/code&gt;&lt;/a&gt; instance provided by a parent Fragment with multiple child Fragments hosting similarly-configured &lt;code&gt;RecyclerView&lt;/code&gt;s. When the parent Fragment’s View hierarchy gets destroyed, the &lt;code&gt;RecycledViewPool&lt;/code&gt; instance will be cleared automatically. A &lt;code&gt;ViewLifecycleLazy&lt;/code&gt; delegate is a good option to expose a View reference outside of the Fragment class, but be careful to only read it when the Fragment has a view hierarchy.&lt;/p&gt;




&lt;p&gt;I hope you enjoyed the quick read (compared to my previous articles) and learned a thing or two about Fragments and Kotlin delegated properties. &lt;em&gt;Let’s continue the conversation in the comments section and on social networks.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>android</category>
      <category>androiddev</category>
      <category>fragments</category>
    </item>
    <item>
      <title>Smarter Shared Kotlin Flows</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Sun, 05 Jun 2022 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/smarter-shared-kotlin-flows-41n0</link>
      <guid>https://dev.to/cbeyls/smarter-shared-kotlin-flows-41n0</guid>
      <description>&lt;p&gt;This is the second part of a series of articles about using Kotlin Flow on Android.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/cbeyls/kotlins-flow-in-viewmodels-its-complicated-livedata-is-still-your-friend-240c"&gt;In the first part&lt;/a&gt;, we described the main limitation of Kotlin Flow when used inside &lt;code&gt;ViewModel&lt;/code&gt; classes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a &lt;code&gt;SharedFlow&lt;/code&gt; or &lt;code&gt;StateFlow&lt;/code&gt; using the &lt;code&gt;SharingStarted.WhileSubscribed()&lt;/code&gt; strategy is collected again after the user navigates back to an Activity or Fragment, its source upstream Flow will always restart from scratch, sometimes resulting in unnecessary work being performed when the previously cached data was still valid.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchResult&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;queryFlow&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;query&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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="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;SearchResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EMPTY&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the above example, &lt;code&gt;repository.search()&lt;/code&gt; will be executed again even if the latest value of &lt;code&gt;queryFlow&lt;/code&gt; didn’t change in the meantime. This means a potential unnecessary network request or database query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;LiveData&lt;/code&gt;&lt;/strong&gt; doesn’t suffer from this issue because its observers don’t need to unsubscribe when they become inactive: LiveData is lifecycle-aware and will postpone the delivery of new results until it becomes active, while also ensuring that the same result will never be delivered to the same observer twice (even when it becomes active again). For more details I invite you to read the full article.&lt;/p&gt;

&lt;p&gt;At the end of this first part, we concluded that there was no simple and correct way to avoid performing this unnecessary work when relying only on the standard &lt;code&gt;shareIn()&lt;/code&gt; or &lt;code&gt;stateIn()&lt;/code&gt; operators.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this second part, we are going to solve that efficiency problem by designing a new Flow operator that will allow &lt;code&gt;SharedFlow&lt;/code&gt;s to integrate better with the lifecycle.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Synchronizing with the Lifecycle
&lt;/h2&gt;
&lt;h3&gt;
  
  
  LiveData
&lt;/h3&gt;

&lt;p&gt;The core reason why &lt;code&gt;LiveData&lt;/code&gt; deals with lifecycles better than &lt;code&gt;Flow&lt;/code&gt; is because the lifecycle state is automatically propagated upstream through all the LiveData instances so they can &lt;strong&gt;all pause cooperatively&lt;/strong&gt; while preserving their state. To be exact, the information that is propagated is a simplified and aggregated lifecycle state called the &lt;strong&gt;active state&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A LiveData instance becomes active&lt;/strong&gt; when at least one of its observers enters the &lt;code&gt;STARTED&lt;/code&gt; lifecycle state. This may happen when a subscribed observer enters the &lt;code&gt;STARTED&lt;/code&gt; state or when a new started observer subscribes;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A LiveData instance becomes inactive&lt;/strong&gt; when none of its observers remains in the &lt;code&gt;STARTED&lt;/code&gt; lifecycle state. This may happen when a subscribed observer moves back from the &lt;code&gt;STARTED&lt;/code&gt; state to the &lt;code&gt;CREATED&lt;/code&gt; state or when a started observer unsubscribes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When applying a &lt;a href="https://developer.android.com/reference/androidx/lifecycle/Transformations" rel="noopener noreferrer"&gt;LiveData transformation&lt;/a&gt; like &lt;code&gt;map()&lt;/code&gt; or &lt;code&gt;switchMap(&lt;/code&gt;), the upstream LiveData instance automatically inherits the active state of the downstream LiveData instance.&lt;/p&gt;

&lt;p&gt;When inactive, LiveData instances will automatically postpone delivering new results to observers downstream. Additionnaly, LiveData implementations may be notified in order to stop doing active work. For example, the &lt;a href="https://developer.android.com/reference/androidx/lifecycle/CoroutineLiveDataKt" rel="noopener noreferrer"&gt;&lt;em&gt;LiveData coroutine builder&lt;/em&gt;&lt;/a&gt; will cancel its coroutine block when it becomes inactive.&lt;/p&gt;
&lt;h3&gt;
  
  
  SharedFlow
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;SharedFlow&lt;/code&gt; (and its subclass &lt;code&gt;StateFlow&lt;/code&gt;) is a special kind of &lt;code&gt;Flow&lt;/code&gt; that is able to broadcast the values emitted by a single source to multiple observers (called &lt;em&gt;collectors&lt;/em&gt;) and replay the latest value to new observers, just like LiveData. &lt;strong&gt;A SharedFlow instance is both a collector &lt;em&gt;and&lt;/em&gt; an emitter of values&lt;/strong&gt;, and the upstream values are collected by SharedFlow independently from the downstream collectors.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Flow&lt;/code&gt; and &lt;code&gt;SharedFlow&lt;/code&gt; do not support the Android &lt;code&gt;Lifecycle&lt;/code&gt; class directly, but &lt;a href="https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda" rel="noopener noreferrer"&gt;AndroidX Lifecycle APIs&lt;/a&gt; like &lt;code&gt;Lifecycle.repeatOnLifecycle()&lt;/code&gt; must be used in the UI layer to synchronize the Flow collection with the Android &lt;code&gt;Lifecycle&lt;/code&gt;: Flows must be collected only when the UI is in the &lt;code&gt;STARTED&lt;/code&gt; lifecycle state or higher and the collecting coroutine should be canceled as soon as the UI becomes invisible.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SharedFlow&lt;/code&gt; implementations like &lt;code&gt;MutableSharedFlow&lt;/code&gt; are also able to expose &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-mutable-shared-flow/subscription-count.html" rel="noopener noreferrer"&gt;&lt;strong&gt;the current number of subscribed collectors&lt;/strong&gt;&lt;/a&gt; which, when used in combination with the Lifecycle synchronization APIs mentioned above, can be used to infer something equivalent to the active state of LiveData:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A SharedFlow instance becomes active&lt;/strong&gt; when the first collector subscribes;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A SharedFlow instance becomes inactive&lt;/strong&gt; when the last collector unsubscribes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/share-in.html" rel="noopener noreferrer"&gt;&lt;code&gt;shareIn()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/state-in.html" rel="noopener noreferrer"&gt;&lt;code&gt;stateIn()&lt;/code&gt;&lt;/a&gt; extension functions are the simplest ways of creating a &lt;code&gt;SharedFlow&lt;/code&gt; instance from a source upstream Flow. They accept a &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-sharing-started/" rel="noopener noreferrer"&gt;&lt;code&gt;SharingStarted&lt;/code&gt;&lt;/a&gt; argument which is the strategy used to start and stop collecting the upstream Flow (from a separate coroutine) in response to the changes of “active state”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In conclusion, &lt;code&gt;SharedFlow&lt;/code&gt; can be made lifecycle-aware, but when using these limited APIs the only thing that can be done in response to an active state change is to launch or cancel a coroutine collecting the entire upstream Flow. The upstream Flow cannot just pause and resume where it left off:&lt;/strong&gt; canceling the coroutine means losing the entire internal state of the current collection and having to restart the upstream Flow from scratch during the next collection.&lt;/p&gt;

&lt;p&gt;This makes it impractical to use operators like &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/distinct-until-changed.html" rel="noopener noreferrer"&gt;&lt;code&gt;distinctUntilChanged()&lt;/code&gt;&lt;/a&gt; in the upstream Flow because the last emitted value will be forgotten as soon as the coroutine collecting the Flow gets canceled by the SharedFlow strategy. &lt;strong&gt;Flow operators are not designed to work across multiple collections.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  An alternative approach
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4i27aqiln51y77u61nh9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4i27aqiln51y77u61nh9.jpg" alt="Morpheus from " width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to find a trade-off. Instead of canceling the coroutine collecting the entire upstream Flow, we should keep it always active but &lt;strong&gt;&lt;em&gt;split&lt;/em&gt; the upstream Flow into 2 parts&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The upper part of the upstream Flow&lt;/strong&gt; should be synchronized with the lifecycle and should stop being collected when the lifecycle is inactive;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The lower part of the upstream Flow&lt;/strong&gt; should never stop being collected but will temporarily not receive any new value from the upper part while the lifecycle is inactive.
&lt;strong&gt;This way, operators like &lt;code&gt;distinctUntilChanged()&lt;/code&gt; could be used in the lower part to successfully filter out values re-emitted by the upper part when it restarts and avoid unnecessary work further down the chain.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&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;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;someTriggerFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                           &lt;span class="c1"&gt;// upper part ↑&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;someOperator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someFormOfLifecycle&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="c1"&gt;// lower part ↓&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="nf"&gt;someExpensiveLoadingOperation&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="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;Eagerly&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;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty&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 approach was proposed by &lt;a href="https://dev.to/hichamboushaba"&gt;Hicham Boushaba&lt;/a&gt; in his article &lt;a href="https://dev.to/hichamboushaba/making-callback-flows-lifecycle-aware-2dai"&gt;“Making cold Flows lifecycle-aware”&lt;/a&gt; which served as a starting point for this one.&lt;/p&gt;

&lt;p&gt;To make the upper part of the Flow lifecycle-aware, &lt;strong&gt;we need to use an operator taking some form of lifecycle as input&lt;/strong&gt;, launching a child coroutine to collect it when the lifecycle is active and canceling the coroutine when inactive, while forwarding the values downstream to the lower part.&lt;/p&gt;
&lt;h3&gt;
  
  
  Injecting an Android &lt;code&gt;Lifecycle&lt;/code&gt; in the ViewModel ?
&lt;/h3&gt;

&lt;p&gt;Mr Boushaba suggested a new operator &lt;code&gt;whenAtLeast()&lt;/code&gt; working in combination with a custom Android Lifecycle-aware ViewModel. A similar option is to use the &lt;a href="https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#(kotlinx.coroutines.flow.Flow).flowWithLifecycle(androidx.lifecycle.Lifecycle,androidx.lifecycle.Lifecycle.State)" rel="noopener noreferrer"&gt;&lt;code&gt;flowWithLifecycle()&lt;/code&gt;&lt;/a&gt; operator provided by the AndroidX Lifecycle library in a standard ViewModel. Both these solutions require keeping a reference to an Android &lt;code&gt;Lifecycle&lt;/code&gt; inside a ViewModel class. In my opinion &lt;strong&gt;this should be avoided&lt;/strong&gt; for different reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It makes the ViewModel more difficult to test because it adds an extra dependency to the &lt;code&gt;Lifecycle&lt;/code&gt; class;&lt;/li&gt;
&lt;li&gt;It requires additional complex code to clear the &lt;code&gt;Lifecycle&lt;/code&gt; references from the ViewModel after the &lt;code&gt;LifecycleOwner&lt;/code&gt; gets destroyed, in order to prevent memory leaks;&lt;/li&gt;
&lt;li&gt;It doesn’t take into account the fact that a single ViewModel may be observed by multiple components with different Lifecycles at the same time. For example it’s common to use a ViewModel to allow a Fragment to communicate with an Activity or another Fragment. Supporting these use cases would require reinventing much of what LiveData already handles out-of-the box;&lt;/li&gt;
&lt;li&gt;There is a simpler solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Introducing the &lt;code&gt;flowWhileShared()&lt;/code&gt; operator
&lt;/h3&gt;

&lt;p&gt;It turns out we &lt;strong&gt;don’t need to deal with Android’s Lifecycle&lt;/strong&gt; at all in the ViewModel because &lt;code&gt;MutableSharedFlow&lt;/code&gt; already provides something equivalent. In the previous section, we mentioned that it tracks and exposes the current number of subscribed collectors through the &lt;code&gt;subscriptionCount&lt;/code&gt; property and this can be used to infer the &lt;strong&gt;active state&lt;/strong&gt; which is all we need. It is used internally by &lt;code&gt;shareIn()&lt;/code&gt; and &lt;code&gt;stateIn()&lt;/code&gt; but can also be used as input value for a custom Flow operator that we are going to call &lt;strong&gt;&lt;code&gt;flowWhileShared()&lt;/code&gt;&lt;/strong&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="nd"&gt;@OptIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExperimentalCoroutinesApi&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&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;flowWhileShared&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;subscriptionCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;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;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;started&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subscriptionCount&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="k"&gt;when&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="nc"&gt;SharingCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;START&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;
                &lt;span class="nc"&gt;SharingCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;SharingCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STOP_AND_RESET_REPLAY_CACHE&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&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;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buffer&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The implementation is straightforward and relies on two existing Flow building blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-sharing-started/" rel="noopener noreferrer"&gt;&lt;code&gt;SharingStarted&lt;/code&gt;&lt;/a&gt; is used to emit a Flow of &lt;code&gt;START&lt;/code&gt; and &lt;code&gt;STOP&lt;/code&gt; commands in reaction to the changes of &lt;code&gt;subscriptionCount&lt;/code&gt;. In 99% of the cases, the implementation we’re going to use is &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-sharing-started/-companion/-while-subscribed.html" rel="noopener noreferrer"&gt;&lt;code&gt;SharingStarted.WhileSubscribed()&lt;/code&gt;&lt;/a&gt; so that the &lt;code&gt;START&lt;/code&gt; command will be emitted when &lt;strong&gt;&lt;code&gt;subscriptionCount &amp;gt; 0&lt;/code&gt;&lt;/strong&gt; and the &lt;code&gt;STOP&lt;/code&gt; command will be emitted when &lt;strong&gt;&lt;code&gt;subscriptionCount == 0&lt;/code&gt;&lt;/strong&gt; to match the behavior of LiveData;&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flat-map-latest.html" rel="noopener noreferrer"&gt;&lt;code&gt;flatMapLatest()&lt;/code&gt;&lt;/a&gt; operator is used to switch between the upstream Flow (&lt;code&gt;this&lt;/code&gt;) and an empty Flow. Internally, this operator creates a child coroutine to collect the values of these Flows and cancels it on each new command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F10d7szbry72tz53uyrkd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F10d7szbry72tz53uyrkd.jpg" alt="A meme with a car on the highway labeled " width="524" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; for simplicity, the special “stop and reset replay cache” command which acts on the cache of the parent SharedFlow is ignored and treated like a regular “stop” command.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Usage with &lt;code&gt;SharedFlow&lt;/code&gt; or &lt;code&gt;StateFlow&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Unfortunately this new operator can’t be used in combination with &lt;code&gt;shareIn()&lt;/code&gt; or &lt;code&gt;stateIn()&lt;/code&gt; because they don’t expose the &lt;code&gt;subscriptionCount&lt;/code&gt; field of &lt;code&gt;MutableSharedFlow&lt;/code&gt; publicly. Instead we need to create and manage our own instance of &lt;code&gt;MutableSharedFlow&lt;/code&gt; or &lt;code&gt;MutableStateFlow&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To reduce boilerplate code and avoid repetition, we can create a custom &lt;code&gt;StateFlow&lt;/code&gt; factory function:&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;stateFlow&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="nc"&gt;CoroutineScope&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;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subscriptionCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;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="nc"&gt;StateFlow&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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&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="n"&gt;initialValue&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="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;producer&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;.&lt;/span&gt;&lt;span class="n"&gt;subscriptionCount&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;collect&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;)&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asStateFlow&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 function immediately launches a coroutine from the provided scope and passes the &lt;code&gt;subscriptionCount&lt;/code&gt; as argument to an upstream Flow &lt;code&gt;producer&lt;/code&gt; lambda. The produced Flow is then collected by the &lt;code&gt;MutableStateFlow&lt;/code&gt; (which implements &lt;code&gt;FlowCollector&amp;lt;T&amp;gt;&lt;/code&gt;) and finally the &lt;code&gt;MutableStateFlow&lt;/code&gt; is returned as a read-only &lt;code&gt;StateFlow&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;At the end of this article you will find the source code of an optimized version of this function (minimizing the number of classes generated by the compiler) and a variant for SharedFlow.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course this entire system only works as intended if all the &lt;code&gt;SharedFlow&lt;/code&gt;s and &lt;code&gt;StateFlow&lt;/code&gt;s in the ViewModel are collected from the UI layer using the AndroidX Lifecycle APIs mentioned above, for example:&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;launch&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="nf"&gt;repeatOnLifecycle&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;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;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nf"&gt;displayResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;h2&gt;
  
  
  Use cases
&lt;/h2&gt;

&lt;p&gt;Let’s look at some real-world examples of how to use these new functions together.&lt;/p&gt;
&lt;h3&gt;
  
  
  Loading data in response to location updates
&lt;/h3&gt;

&lt;p&gt;Suppose we have a &lt;code&gt;locationFlow()&lt;/code&gt; function similar to the one described in &lt;a href="https://medium.com/androiddevelopers/simplifying-apis-with-coroutines-and-flow-a6fb65338765" rel="noopener noreferrer"&gt;this article&lt;/a&gt; which allows receiving location updates in the form of a cold &lt;code&gt;Flow&amp;lt;Location&amp;gt;&lt;/code&gt;, actively using the device’s GPS while collected. We want to load a list of shops around the current location from an API and update that list every time the device moves by &lt;strong&gt;at least 30 meters&lt;/strong&gt; to avoid unnecessary API calls. At the same time, we want to make sure the GPS resource is freed while the screen is not visible.&lt;/p&gt;

&lt;p&gt;The ViewModel will contain a &lt;code&gt;StateFlow&lt;/code&gt; builder similar 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="nd"&gt;@OptIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExperimentalCoroutinesApi&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&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;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Shop&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;stateFlow&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="nf"&gt;emptyList&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;subscriptionCount&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;locationClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locationFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20000L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;smallestDisplacement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;30f&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flowWhileShared&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;subscriptionCount&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="mi"&gt;1000L&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="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="n"&gt;old&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;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;30f&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="n"&gt;shopsRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getShopsAtLocation&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="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;emptyList&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;&lt;em&gt;(Error handling has been simplified for the demonstration)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;stateFlow()&lt;/code&gt;&lt;/strong&gt; factory function takes a producer lambda returning the upstream Flow as last argument. That lambda allows &lt;code&gt;subscriptionCount&lt;/code&gt; to be used in the upstream Flow.&lt;/p&gt;

&lt;p&gt;The main part of the upstream Flow will be collected with no interruption as long as the ViewModel stays in memory. However the part before &lt;code&gt;flowWhileShared()&lt;/code&gt;, in this case &lt;code&gt;locationFlow()&lt;/code&gt;, will only be collected while the &lt;code&gt;StateFlow&lt;/code&gt; is active (has at least one subscription) so the GPS will stop when it becomes inactive. Thanks to the &lt;code&gt;SharingStarted.WhileSubscribed(1000L)&lt;/code&gt; strategy, the collection will be canceled one second after the UI is hidden and the number of subscriptions reaches 0. &lt;strong&gt;That extra delay allows to avoid the cost of restarting location updates from scratch during configuration changes (when a new UI instance will resume the Flow collection almost immediately).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the user leaves the screen and comes back to it later, the collection of &lt;code&gt;locationFlow()&lt;/code&gt; will restart and &lt;code&gt;distinctUntilChanged()&lt;/code&gt; (which is still being collected with no interruption) will take care of filtering out new locations that are too close to the previously emitted one. This way, &lt;strong&gt;we avoid the unnecessary work of calling the API again&lt;/strong&gt; if the device did not move more than 30 meters since the last time the UI was visible.&lt;/p&gt;

&lt;p&gt;The latest result will still be cached by &lt;code&gt;StateFlow&lt;/code&gt; and automatically replayed to the current UI when it starts collecting it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;We managed to create the most efficient implementation solving that problem without having to rely on &lt;code&gt;LiveData&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Reloading data on invalidation
&lt;/h3&gt;

&lt;p&gt;Whenever possible, an application should present the latest version of the data to the user without the need of a manual refresh. To achieve this, a repository can send an invalidation signal to the observer of the data after each completed write operation (create/update/delete), eventually triggering a refresh.&lt;/p&gt;

&lt;p&gt;To achieve maximum efficiency, the data should only be reloaded from storage or network if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The screen is currently visible (no early refresh in the background);&lt;/li&gt;
&lt;li&gt;The data has actually changed since the last load.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A natural way to represent data that can be invalidated is to &lt;strong&gt;return a Flow of results from the repository&lt;/strong&gt;, rather than a single result.&lt;/p&gt;

&lt;p&gt;However since we want to avoid refreshing the data while the screen is not visible, we need to cancel the collection of that Flow during that time. And since each Flow collection is self-contained, it will always start by loading the data, &lt;strong&gt;no matter if it has changed or not since the previous collection from the same screen&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, this kind of Flow is created by the &lt;em&gt;Room&lt;/em&gt; Jetpack library to provide support for &lt;a href="https://developer.android.com/training/data-storage/room/async-queries#options" rel="noopener noreferrer"&gt;observable data sets in your DAOs&lt;/a&gt;. The Room implementation performs a database query when the Flow collection starts, then every time a related table is updated. &lt;strong&gt;This means that an unnecessary database query is performed every time a screen becomes visible again and the data set hasn’t changed in the meantime.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;By comparison, the LiveData implementation generated by the older versions of Room is more efficient because it will only perform a database query if a table has changed since the last time the LiveData was active.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make the Kotlin Flow code more efficient we need to use &lt;strong&gt;versioning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The version of the data set should be exposed as a &lt;strong&gt;&lt;code&gt;StateFlow&amp;lt;Int&amp;gt;&lt;/code&gt;&lt;/strong&gt; in the repository, along with functions to retrieve current snapshots of the data. For example:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;CustomerRepository&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;customersVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getAllCustomers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getActiveCustomers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;&amp;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 repository may be backed by a remote API or local storage like a database; it doesn’t matter.&lt;/p&gt;

&lt;p&gt;Every time the data set is updated successfully, the version number must be incremented atomically:&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;_customersVersion&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;updateCustomerName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Insert some code to update the data here&lt;/span&gt;
    &lt;span class="n"&gt;_customersVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&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="mi"&gt;1&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;&lt;strong&gt;Tip:&lt;/strong&gt; if your repository is backed by a &lt;em&gt;Room&lt;/em&gt; database, you don’t need to keep track of changes manually, you can use Room’s &lt;code&gt;invalidationTrackerFlow()&lt;/code&gt; to monitor a list of tables:&lt;/p&gt;


&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;RoomDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createVersionFlow&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="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;vararg&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;Int&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;flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="nf"&gt;invalidationTrackerFlow&lt;/span&gt;&lt;span class="p"&gt;(*&lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version&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="nf"&gt;conflate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shareIn&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;scope&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;Eagerly&lt;/span&gt;&lt;span class="p"&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="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;All the pieces of the puzzle are finally put together in the 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="nd"&gt;@OptIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExperimentalCoroutinesApi&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&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;activeCustomers&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;stateFlow&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="nf"&gt;emptyList&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;subscriptionCount&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;customersRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customersVersion&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flowWhileShared&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;subscriptionCount&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="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;mapLatest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;customersRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveCustomers&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;Thanks again to the &lt;code&gt;distinctUntilChanged()&lt;/code&gt; operator, the current version is compared against the previous one (if any) as soon as the &lt;code&gt;StateFlow&lt;/code&gt; becomes active, and &lt;strong&gt;the data is only loaded if the version number changed&lt;/strong&gt;. Problem solved.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl1bzymx1pd4qyx0y07rn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl1bzymx1pd4qyx0y07rn.png" alt="Marbles visualisation of the distinctUntilChanged() operator" width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;
Illustration from &lt;a href="https://flowmarbles.com/" rel="noopener noreferrer"&gt;flowmarbles.com&lt;/a&gt;


&lt;h2&gt;
  
  
  Final tips
&lt;/h2&gt;

&lt;p&gt;For many cases, the standard &lt;code&gt;shareIn()&lt;/code&gt; and &lt;code&gt;stateIn()&lt;/code&gt; operators should still be preferred over the complexity of &lt;code&gt;flowWhileShared()&lt;/code&gt;. In particular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For one-shot data loading&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When the source of the upstream Flow is a UI element on the screen&lt;/strong&gt; like a refresh button, thus new values will never be emitted when the screen is invisible and the upstream Flow collection doesn’t need to be canceled;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When the cost of reloading the same data from the repository is cheap&lt;/strong&gt;, for example because the implementation is backed by a shared cache. It’s then acceptable to reload data every time the screen becomes visible.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using the new &lt;code&gt;flowWhileShared()&lt;/code&gt; operator, we managed to synchronize a portion of an upstream Flow with the lifecycle of the downstream &lt;code&gt;SharedFlow&lt;/code&gt; or &lt;code&gt;StateFlow&lt;/code&gt;, allowing to skip unnecessary work with the help of an operator like &lt;code&gt;distinctUntilChanged()&lt;/code&gt;. All of this without having to include any LiveData or Android-specific Lifecycle code in the ViewModel of Android applications.&lt;/p&gt;
&lt;h2&gt;
  
  
  Full source code
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;






&lt;p&gt;If you liked this article and found it helpful, please share it on social networks and post your feedback in the comments section. I’m curious to learn what you think about this pattern and how it could be improved. Expect reading about more uses cases for Kotlin Flow on Android in a following part.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Special thanks to &lt;a href="https://dev.to/hichamboushaba"&gt;Hicham Boushaba&lt;/a&gt; who gave me the original idea for writing this blog post.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>androiddev</category>
      <category>android</category>
      <category>flow</category>
    </item>
    <item>
      <title>Kotlin’s Flow in ViewModels: it’s complicated (LiveData is still your friend)</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Fri, 27 Aug 2021 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/kotlins-flow-in-viewmodels-its-complicated-livedata-is-still-your-friend-240c</link>
      <guid>https://dev.to/cbeyls/kotlins-flow-in-viewmodels-its-complicated-livedata-is-still-your-friend-240c</guid>
      <description>&lt;p&gt;Loading UI data in Android applications can be challenging. The &lt;a href="https://developer.android.com/guide/components/activities/activity-lifecycle" rel="noopener noreferrer"&gt;&lt;strong&gt;lifecycle&lt;/strong&gt;&lt;/a&gt; of the various screens need to be taken into account, as well as &lt;strong&gt;configuration changes&lt;/strong&gt; leading to the destruction and recreation of Activities.&lt;/p&gt;

&lt;p&gt;The individual screens of an app constantly toggle between &lt;strong&gt;interactive&lt;/strong&gt; and &lt;strong&gt;hidden&lt;/strong&gt; as the user navigates further and back in an app, switches from one app to another, or the device screen gets locked or unlocked. Each component needs to play fair and only perform active work when given the ball.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration changes&lt;/strong&gt; happen on various occasions: when changing the device orientation, switching the app to multi-window mode or resizing its window size, switching to dark or light mode, changing the default locale or font sizes, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goals of efficiency
&lt;/h2&gt;

&lt;p&gt;To achieve efficient data loading in Activities and Fragments leading to the best user experience, the following should be considered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Caching&lt;/strong&gt;: data that has been loaded successfully and is still valid should be delivered immediately and not loaded a second time. In particular, when an existing Activity or Fragment becomes &lt;em&gt;visible again&lt;/em&gt;, or after an Activity gets &lt;em&gt;recreated&lt;/em&gt; on configuration change;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoiding background work&lt;/strong&gt;: when an Activity or Fragment becomes invisible (moves from the &lt;code&gt;STARTED&lt;/code&gt; to the &lt;code&gt;CREATED&lt;/code&gt; state), any ongoing loading work should be paused or canceled in order to save resources. This is especially important for &lt;em&gt;endless streams of data&lt;/em&gt; like location updates or periodic refreshes of any kind;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No work interruption during configuration changes&lt;/strong&gt;: this is an exception to the second goal. During configuration changes, an Activity gets &lt;em&gt;replaced&lt;/em&gt; by a new instance of it while preserving its state, so canceling ongoing work when the old instance is destroyed to immediately restart it when the new instance is created would be counter-productive.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Today: ViewModel and LiveData
&lt;/h2&gt;

&lt;p&gt;To help developers reach these goals with code of manageable complexity, Google released the first &lt;a href="https://developer.android.com/topic/libraries/architecture" rel="noopener noreferrer"&gt;&lt;strong&gt;Architecture Components&lt;/strong&gt;&lt;/a&gt; libraries in 2017 in the form of &lt;strong&gt;&lt;code&gt;ViewModel&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;LiveData&lt;/code&gt;&lt;/strong&gt;. This was before Kotlin was introduced as the recommended programming language to develop Android applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/topic/libraries/architecture/viewmodel" rel="noopener noreferrer"&gt;&lt;strong&gt;ViewModels&lt;/strong&gt;&lt;/a&gt; are objects preserved across configuration changes. They are useful to reach goals &lt;strong&gt;#1&lt;/strong&gt; and &lt;strong&gt;#3&lt;/strong&gt;: loading operations can run &lt;em&gt;uninterrupted&lt;/em&gt; inside of them during configuration changes, while the resulting data can be &lt;em&gt;cached&lt;/em&gt; in them and shared with one or more Fragments/Activity currently attached to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/topic/libraries/architecture/livedata" rel="noopener noreferrer"&gt;&lt;strong&gt;LiveData&lt;/strong&gt;&lt;/a&gt; is a simple observable data holder class that is also &lt;em&gt;lifecycle-aware&lt;/em&gt;. New values are only dispatched to observers when their lifecycle is at least in the &lt;code&gt;STARTED&lt;/code&gt; (visible) state, and observers are unregistered automatically which is handy to avoid memory leaks. LiveData is useful to reach goals &lt;strong&gt;#1&lt;/strong&gt; and &lt;strong&gt;#2&lt;/strong&gt;: it caches the &lt;em&gt;latest value&lt;/em&gt; of the data it holds and that value is automatically dispatched to new observers. Plus, it is notified when there are no more registered observers in the &lt;code&gt;STARTED&lt;/code&gt; state, which allows to avoid performing unnecessary background work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foxz80tlyw7h8fdj94sak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foxz80tlyw7h8fdj94sak.png" alt="The ViewModel lifecycle" width="522" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you are an experienced Android developer, you probably know all of this already. But it’s important to recap these features in order to compare them with those of &lt;strong&gt;Flow&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  LiveData + Coroutines
&lt;/h2&gt;

&lt;p&gt;LiveData itself is quite limited compared to reactive streams solutions like RxJava:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It only handles passing data &lt;strong&gt;to and from the main thread&lt;/strong&gt;, leaving the burden of managing background threads to the developer.&lt;/li&gt;
&lt;li&gt;Notably, the &lt;a href="https://developer.android.com/reference/androidx/lifecycle/Transformations#(androidx.lifecycle.LiveData).map(kotlin.Function1)" rel="noopener noreferrer"&gt;&lt;code&gt;map()&lt;/code&gt;&lt;/a&gt; operator executes its transformation function on the main thread and cannot be used to perform I/O operations or heavy CPU work. For that case the &lt;a href="https://developer.android.com/reference/androidx/lifecycle/Transformations#(androidx.lifecycle.LiveData).switchMap(kotlin.Function1)" rel="noopener noreferrer"&gt;&lt;code&gt;switchMap()&lt;/code&gt;&lt;/a&gt; operator needs to be used, in combination with manually launching an asynchronous operation on a background thread, even if only a single value has to be posted back on the main thread.&lt;/li&gt;
&lt;li&gt;Only &lt;a href="https://developer.android.com/reference/androidx/lifecycle/Transformations#map(androidx.lifecycle.LiveData%3CX%3E,%20androidx.arch.core.util.Function%3CX,%20Y%3E)" rel="noopener noreferrer"&gt;3 transformation operators&lt;/a&gt; are provided for LiveData: &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;switchMap()&lt;/code&gt; and &lt;code&gt;distinctUntilChanged()&lt;/code&gt;. If more are needed, you must implement them yourself using &lt;code&gt;MediatorLiveData&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To help overcome these limitations, the Jetpack libraries also provide bridges from LiveData to other technologies like RxJava or Kotlin’s coroutines.&lt;/p&gt;

&lt;p&gt;The simplest and most elegant bridge in my opinion is the &lt;a href="https://developer.android.com/reference/androidx/lifecycle/CoroutineLiveDataKt" rel="noopener noreferrer"&gt;&lt;strong&gt;LiveData coroutine builder&lt;/strong&gt;&lt;/a&gt; function. This function is similar to the &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow.html" rel="noopener noreferrer"&gt;&lt;code&gt;flow {}&lt;/code&gt; builder function&lt;/a&gt; from the Kotlin Coroutines library and allows to smartly wrap a coroutine as a &lt;code&gt;LiveData&lt;/code&gt; instance:&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;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;liveData&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;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someSuspendingFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;ul&gt;
&lt;li&gt;You can use all the power of coroutines and coroutine contexts to write asynchronous code in a synchronous way without callbacks, switching between threads automatically as needed;&lt;/li&gt;
&lt;li&gt;New values are dispatched to the LiveData observers on the main thread by calling the &lt;code&gt;emit()&lt;/code&gt; or &lt;code&gt;emitSource()&lt;/code&gt; suspending functions from the coroutine;&lt;/li&gt;
&lt;li&gt;The coroutine uses a special scope and lifecycle tied to the LiveData instance. When the LiveData becomes &lt;em&gt;inactive&lt;/em&gt; (has no more observer in the &lt;code&gt;STARTED&lt;/code&gt; state), the coroutine will automatically be canceled, allowing to reach goal &lt;strong&gt;#2&lt;/strong&gt; without having to do any extra work;&lt;/li&gt;
&lt;li&gt;The cancellation of the coroutine will actually be &lt;strong&gt;delayed by 5 seconds&lt;/strong&gt; after the LiveData becomes inactive in order to handle configuration changes gracefully: if a new Activity immediately replaces the old one and the LiveData becomes active again &lt;em&gt;before the timeout&lt;/em&gt;, cancellation will not happen and the cost of an unnecessary restart will be avoided (goal &lt;strong&gt;#3&lt;/strong&gt;);&lt;/li&gt;
&lt;li&gt;If the user comes back to the screen and the LiveData becomes &lt;em&gt;active&lt;/em&gt; again, the coroutine will automatically restart, but &lt;strong&gt;only if it was previously canceled before completion&lt;/strong&gt;. As soon as the coroutine completes it will not restart anymore, allowing to avoid loading the same data twice if the input did not change (goal &lt;strong&gt;#1&lt;/strong&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conclusion: by using the LiveData coroutines builder you get &lt;strong&gt;the best behavior by default&lt;/strong&gt; with the simplest code.&lt;/p&gt;

&lt;p&gt;Instead of suspending functions returning a single value, what if a repository provides functions returning a &lt;em&gt;stream of values&lt;/em&gt; in the form of a &lt;strong&gt;&lt;code&gt;Flow&lt;/code&gt;&lt;/strong&gt;? It is also possible to convert it to a &lt;code&gt;LiveData&lt;/code&gt; and take advantage of all the above features by using the &lt;code&gt;asLiveData()&lt;/code&gt; extension function:&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;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someFunctionReturningFlow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;asLiveData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, &lt;code&gt;asLiveData()&lt;/code&gt; also uses the LiveData coroutines builder to create a simple coroutine collecting the Flow while the LiveData is active:&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;asLiveData&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;LiveData&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="nf"&gt;liveData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;emit&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But let’s pause for a moment — what exactly is a &lt;code&gt;Flow&lt;/code&gt; and is it possible to use it as a complete replacement for &lt;code&gt;LiveData&lt;/code&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Kotlin’s Flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8aftly5slisjwn1mmh9c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8aftly5slisjwn1mmh9c.jpg" alt="A retro version of the Jealous Girlfriend meme with Charlie Chaplin looking at Flow and neglecting LiveData" width="725" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
Flow is newer and trendy so it must be better in every aspect, right?



&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/coroutines-flow.html" rel="noopener noreferrer"&gt;&lt;code&gt;Flow&lt;/code&gt;&lt;/a&gt; is a class from Kotlin’s &lt;a href="https://github.com/Kotlin/kotlinx.coroutines" rel="noopener noreferrer"&gt;Coroutines library&lt;/a&gt; introduced in 2019 which represents a &lt;strong&gt;stream of values&lt;/strong&gt; computed asynchronously. It’s similar in concept to RxJava Observables but is based on coroutines and has a simpler API.&lt;/p&gt;

&lt;p&gt;At first, only &lt;strong&gt;cold flows&lt;/strong&gt; were available: stateless streams that are created on demand each time an observer starts collecting their values in the scope of a coroutine. Each observer gets its own sequence of values, they are not shared.&lt;/p&gt;

&lt;p&gt;Later, new &lt;strong&gt;hot flows&lt;/strong&gt; subtypes &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-shared-flow/" rel="noopener noreferrer"&gt;&lt;code&gt;SharedFlow&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/" rel="noopener noreferrer"&gt;&lt;code&gt;StateFlow&lt;/code&gt;&lt;/a&gt; were added and graduated as stable APIs in release 1.4.0 of the Coroutines library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;SharedFlow&lt;/code&gt;&lt;/strong&gt; allows to publish values that are broadcast to all observers. It can manage an optional replay cache and/or a buffer and basically replaces all variants of the deprecated &lt;code&gt;BroadcastChannel&lt;/code&gt; API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;StateFlow&lt;/code&gt;&lt;/strong&gt; is a specialized and optimized subclass of &lt;code&gt;SharedFlow&lt;/code&gt; which stores and replays the &lt;em&gt;latest value&lt;/em&gt; only. Sounds familiar?&lt;/p&gt;

&lt;h3&gt;
  
  
  StateFlow and LiveData have a lot in common:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;They are observable classes&lt;/li&gt;
&lt;li&gt;They store and broadcast the latest value to any number of observers&lt;/li&gt;
&lt;li&gt;They force you to catch exceptions early: an uncaught &lt;code&gt;Exception&lt;/code&gt; in a LiveData callback stops the application. An uncaught &lt;code&gt;Exception&lt;/code&gt; in a hot Flow ends the stream with no possibility to restart it, even when using the &lt;code&gt;.catch()&lt;/code&gt; operator.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  But they also have important differences:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MutableStateFlow&lt;/code&gt; requires an initial value, &lt;code&gt;MutableLiveData&lt;/code&gt; does not (note: &lt;code&gt;MutableSharedFlow(replay = 1)&lt;/code&gt; can be used to emulate a &lt;code&gt;MutableStateFlow&lt;/code&gt; with no initial value, but its implementation is a bit less efficient)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;StateFlow&lt;/code&gt; always filters out repetitions of the same value using &lt;code&gt;Any.equals()&lt;/code&gt; for comparison, &lt;code&gt;LiveData&lt;/code&gt; does not unless combined with the &lt;code&gt;distinctUntilChanged()&lt;/code&gt; operator (note: a &lt;code&gt;SharedFlow&lt;/code&gt; can also be used to prevent this behavior)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;StateFlow&lt;/code&gt; is &lt;strong&gt;not lifecycle-aware&lt;/strong&gt;. However, a &lt;code&gt;Flow&lt;/code&gt; can be collected from a lifecycle-aware coroutine which requires more code to setup without using &lt;code&gt;LiveData&lt;/code&gt; (more details below)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LiveData&lt;/code&gt; uses versioning to keep track of which value has been dispatched to which observer. This allows to avoid dispatching the same value twice to the same observer when it moves back to the &lt;code&gt;STARTED&lt;/code&gt; state.
&lt;code&gt;StateFlow&lt;/code&gt; has &lt;strong&gt;no versioning&lt;/strong&gt;. Each time a coroutine collects a &lt;code&gt;Flow&lt;/code&gt;, &lt;strong&gt;it is considered as a new observer&lt;/strong&gt; and will always receive the latest value first. &lt;strong&gt;This can lead to performing duplicate work&lt;/strong&gt; as we will see in the following case study.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Observing &lt;code&gt;LiveData&lt;/code&gt; vs Collecting &lt;code&gt;Flow&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Observing a LiveData instance from an Activity of Fragment is straightforward:&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;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&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="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;displayResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;It’s a one-time operation and LiveData takes care of syncing the stream with the lifecycle of the observers.&lt;/p&gt;

&lt;p&gt;The equivalent operation for a Flow is called &lt;em&gt;collecting&lt;/em&gt; and collection needs to be done from a coroutine. Because a Flow itself is not lifecycle-aware, the responsibility of syncing with the lifecycle is moved up to the coroutine collecting the Flow.&lt;/p&gt;

&lt;p&gt;To create a lifecycle-aware coroutine collecting a Flow while an Activity/Fragment is in the &lt;code&gt;STARTED&lt;/code&gt; state and cancel the collection automatically when the Activity/Fragment is destroyed, the following code can be used:&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="nf"&gt;displayResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;But there is a major limitation with this code: &lt;strong&gt;it will only work properly with cold flows not backed by a channel or buffer&lt;/strong&gt;. Such a flow is only driven by the coroutine collecting it: when the Activity/Fragment moves back to the &lt;code&gt;CREATED&lt;/code&gt; state, the coroutine will suspend, the Flow producer will suspend along and nothing else will happen until the coroutine is resumed.&lt;/p&gt;

&lt;p&gt;However, there are other kinds of flows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;hot flows&lt;/strong&gt; which are always active and will dispatch results to all current observers (including the suspended ones);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;callback-based or channel-based cold flows&lt;/strong&gt; which subscribe to an active data source when collection starts and only stop the subscription when the collection is canceled (not suspended).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For these cases, &lt;strong&gt;the underlying flow producer will be kept active&lt;/strong&gt; even when the coroutine collecting the Flow is suspended, buffering new results in the background. Resources are wasted and goal &lt;strong&gt;#2&lt;/strong&gt; is missed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmc5korg9bav8roxd85r3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmc5korg9bav8roxd85r3.jpg" alt="Forrest Gump on a bench saying " width="500" height="735"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update (2023):&lt;/strong&gt; &lt;code&gt;launchWhenStarted()&lt;/code&gt; has been fully deprecated for the reasons mentioned above and should not be used anymore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A safer way to collect Flows of any kind needs to be implemented. The coroutine performing the collection must be canceled when the Activity/Fragment becomes invisible and restarted when it becomes visible again, exactly like what the LiveData coroutine builder does. For this purpose, new APIs were introduced in &lt;code&gt;lifecycle:lifecycle-runtime-ktx:2.4.0&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;launch&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="nf"&gt;repeatOnLifecycle&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;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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nf"&gt;displayResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;or alternatively:&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;launch&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;result&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="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;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nf"&gt;displayResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;As you can see, to achieve the same level of safety and efficiency, observing results from an Activity or Fragment is simpler with LiveData.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You can learn more about these new APIs in the article &lt;a href="https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda" rel="noopener noreferrer"&gt;“A safer way to collect flows from Android UIs”&lt;/a&gt; from Manuel Vivo.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Replacing &lt;code&gt;LiveData&lt;/code&gt; with &lt;code&gt;StateFlow&lt;/code&gt; in ViewModels
&lt;/h2&gt;

&lt;p&gt;Let’s go back to the ViewModel. We established that this is a simple and efficient way to fetch data asynchronously using LiveData:&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;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;liveData&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;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someSuspendingFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;How can we achieve the same effect using &lt;code&gt;StateFlow&lt;/code&gt; in place of &lt;code&gt;LiveData&lt;/code&gt;? &lt;em&gt;Jose Alcérreca&lt;/em&gt; wrote &lt;a href="https://medium.com/androiddevelopers/migrating-from-livedata-to-kotlins-flow-379292f419fb" rel="noopener noreferrer"&gt;a long migration guide&lt;/a&gt; to help answer this question. Long story short, for the above use case the equivalent code is:&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;result&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;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flow&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;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someSuspendingFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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="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;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Loading&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;code&gt;stateIn()&lt;/code&gt; operator transforms our cold flow into a hot flow able to share a single result between multiple observers. Thanks to &lt;code&gt;SharingStarted.WhileSubscribed(5000L)&lt;/code&gt;, the hot flow is started lazily when the first observer subscribes and is canceled 5 seconds after the last observer unsubscribes, allowing to avoid doing unnecessary work in the background while also taking configuration changes into account.&lt;/p&gt;

&lt;p&gt;Unfortunately, contrary to the LiveData coroutine builder, &lt;strong&gt;the upstream flow will always be restarted&lt;/strong&gt; automatically by the sharing coroutine when a new observer subscribes after that inactivity period, &lt;strong&gt;even if it reached its end during the previous collection&lt;/strong&gt;. For the above example, it means that &lt;code&gt;someSuspendingFunction()&lt;/code&gt; will always run again if an Activity/Fragment becomes visible after being hidden for more than 5 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal #1 is missed: the data is indeed cached (&lt;code&gt;StateFlow&lt;/code&gt; will store and replay the latest value), but this will not prevent it from being loaded a second time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It looks like we managed to achieve 2 goals out of 3 and replicate most of the behavior of LiveData using code that is a bit more complex.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There remains another small key difference: each time a new flow collection starts, &lt;code&gt;StateFlow&lt;/code&gt; will always immediately deliver the latest result to the observer. &lt;strong&gt;Even if that same result had already been delivered to the same Activity/Fragment instance during the previous collection.&lt;/strong&gt; Because unlike LiveData, StateFlow doesn’t support versioning and each flow collection is considered as a brand new observer.&lt;/p&gt;

&lt;p&gt;Is that problematic? For this simple use case, not really: an Activity or Fragment could just perform an extra check to avoid updating the View if the data hasn’t changed.&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;launch&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;result&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="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;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;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nf"&gt;displayResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;But problems may arise in more complicated, real-life use cases, as we’ll see in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;StateFlow&lt;/code&gt; as trigger in a ViewModel
&lt;/h2&gt;

&lt;p&gt;A common scenario is to use a trigger-based approach to load data in a ViewModel: every time the trigger value is updated, the data gets refreshed.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;MutableLiveData&lt;/code&gt; this works very well:&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;MyViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&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;trigger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;trigger&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="n"&gt;query&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;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchResult&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;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;switchMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="nf"&gt;liveData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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;ul&gt;
&lt;li&gt;On refresh, the &lt;code&gt;switchMap()&lt;/code&gt; operator will connect the observers to a new underlying &lt;code&gt;LiveData&lt;/code&gt; source, replacing the old one. And because the above example uses the LiveData coroutine builder, the previous &lt;code&gt;LiveData&lt;/code&gt; source will automatically cancel its associated coroutine 5 seconds after being disconnected from its observers. Work on obsolete values is avoided with a small delay.&lt;/li&gt;
&lt;li&gt;Because LiveData has versioning, the &lt;code&gt;MutableLiveData&lt;/code&gt; trigger will only dispatch the new value &lt;strong&gt;once&lt;/strong&gt; to the &lt;code&gt;switchMap()&lt;/code&gt; operator, as soon as there is at least one active observer. Later, when observers become inactive and active again, the work of the latest underlying LiveData source will just resume where it left off.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code is simple enough and reaches all goals of efficiency.&lt;/p&gt;

&lt;p&gt;Now let’s see if we can implement the same logic using &lt;strong&gt;&lt;code&gt;MutableStateFlow&lt;/code&gt;&lt;/strong&gt; in place of &lt;code&gt;MutableLiveData&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The naive approach
&lt;/h3&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;MyViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&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;trigger&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="s"&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;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;trigger&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="n"&gt;query&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;results&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;SearchResult&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;trigger&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;query&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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="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;SearchResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EMPTY&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 API of &lt;code&gt;MutableLiveData&lt;/code&gt; and &lt;code&gt;MutableStateFlow&lt;/code&gt; being very close, the trigger code looks almost identical. The biggest difference is the usage of the &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/map-latest.html" rel="noopener noreferrer"&gt;&lt;code&gt;mapLatest()&lt;/code&gt;&lt;/a&gt; transformation function which is equivalent to LiveData’s &lt;code&gt;switchMap()&lt;/code&gt; for a single return value (for multiple return values, &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flat-map-latest.html" rel="noopener noreferrer"&gt;&lt;code&gt;flatMapLatest()&lt;/code&gt;&lt;/a&gt; should be used).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mapLatest()&lt;/code&gt; works like &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/map.html" rel="noopener noreferrer"&gt;&lt;code&gt;map()&lt;/code&gt;&lt;/a&gt; but instead of fully executing the transformation on all input values in sequence, the input values are consumed immediately and the transformation is executed asynchronously in a &lt;strong&gt;separate coroutine&lt;/strong&gt;. When a new value is emitted in the upstream flow, the transformation coroutine for the previous value &lt;strong&gt;will be canceled immediately&lt;/strong&gt; if it was still running and a new one will be launched to replace it. This way, work on obsolete values is avoided.&lt;/p&gt;

&lt;p&gt;So far so good. However, here comes the major problem with this code: because &lt;code&gt;StateFlow&lt;/code&gt; does not support versioning, the trigger will &lt;strong&gt;re-emit the latest value&lt;/strong&gt; when the flow collection restarts. This happens &lt;strong&gt;every time the Activity/Fragment becomes visible again&lt;/strong&gt; after being invisible for more than 5 seconds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F31d67twvnt3p0d9t21rm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F31d67twvnt3p0d9t21rm.jpg" alt="Britney Spears signing " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And when the trigger re-emits the same value, the &lt;code&gt;mapLatest()&lt;/code&gt; transformation will run again, hitting the repository one more time with the same arguments, even though the result had already been delivered and cached!&lt;br&gt;
Goal &lt;strong&gt;#1&lt;/strong&gt; is missed: data that is still valid should not be loaded a second time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Preventing re-emission of the latest trigger value
&lt;/h3&gt;

&lt;p&gt;The next questions that come to mind are: should we prevent this re-emission and how? &lt;code&gt;StateFlow&lt;/code&gt; already takes care of deduplicating values from &lt;em&gt;within a flow collection&lt;/em&gt;, and the &lt;code&gt;distinctUntilChanged()&lt;/code&gt; operator does the same for other kinds of flows. But no standard operator exists to deduplicate values &lt;em&gt;across multiple collections&lt;/em&gt; of the same flow, because flow collections are supposed to be &lt;strong&gt;self-contained&lt;/strong&gt;. This is a major difference with LiveData.&lt;/p&gt;

&lt;p&gt;In the specific case of a Flow shared between multiple observers using the &lt;code&gt;stateIn()&lt;/code&gt; operator, emitted values will be cached and there will always be at most one coroutine collecting the source Flow at any given time. It looks tempting to hack around some operator function that would remember the latest value of a previous collection to be able to skip it when a new collection starts:&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="c1"&gt;// Don't do this at home (or at work)&lt;/span&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;rememberLatest&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="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NULL&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;collectIndexed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;index&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;-&amp;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;index&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="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;!==&lt;/span&gt; &lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;emit&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="n"&gt;latest&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="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;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Remark:&lt;/strong&gt; an attentive reader noted that the same behavior can be achieved by replacing the &lt;code&gt;MutableStateFlow&lt;/code&gt; with a &lt;code&gt;Channel(capacity = CONFLATED)&lt;/code&gt; then turning it into a Flow using &lt;a href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/receive-as-flow.html" rel="noopener noreferrer"&gt;&lt;code&gt;receiveAsFlow()&lt;/code&gt;&lt;/a&gt;. Channels never re-emit values.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately &lt;strong&gt;the above logic is flawed&lt;/strong&gt; and will not work as intended when the downstream flow transformation is &lt;strong&gt;canceled before completion&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The code assumes that after &lt;code&gt;emit(value)&lt;/code&gt; returns, the value has been processed and should not be emitted again if the flow collection restarts, but &lt;strong&gt;this is only true when using unbuffered Flow operators&lt;/strong&gt;. Operators like &lt;code&gt;mapLatest()&lt;/code&gt; are buffered and in this case &lt;code&gt;emit(value)&lt;/code&gt; will return immediately while the transformation is executed asynchronously. This means that &lt;strong&gt;there is no way to know when a value has been fully processed by the downstream flow&lt;/strong&gt;. If the flow collection is canceled in the middle of an asynchronous transformation, &lt;strong&gt;we still need to re-emit the latest value&lt;/strong&gt; when the flow collection restarts in order to resume that transformation, otherwise that value will be lost!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;TL; DR:&lt;/strong&gt; Using &lt;code&gt;StateFlow&lt;/code&gt; as a trigger in a ViewModel leads to repeating work every time the Activity/Fragment becomes visible again and there is no simple way to avoid it.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is why &lt;code&gt;LiveData&lt;/code&gt; is superior to &lt;code&gt;StateFlow&lt;/code&gt; when used as a trigger in a ViewModel, even though these differences are not mentioned in Google’s &lt;a href="https://developer.android.com/codelabs/advanced-kotlin-coroutines#11" rel="noopener noreferrer"&gt;“Advanced coroutines with Kotlin Flow” codelab&lt;/a&gt; which implies the Flow implementation behaves the exact same way as the LiveData one. It does not.&lt;/p&gt;




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

&lt;p&gt;Here are my recommendations based on the above demonstration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep using &lt;code&gt;LiveData&lt;/code&gt; in your Android UI layer and ViewModels, especially for triggers. Use it whenever possible to expose data to be consumed in Activities and Fragments: it will make your code both simple and efficient;&lt;/li&gt;
&lt;li&gt;The LiveData coroutine builder function is your friend and can replace Flows in ViewModels in many cases;&lt;/li&gt;
&lt;li&gt;You can still use the power of Flow operators when you need them, then convert the resulting &lt;code&gt;Flow&lt;/code&gt; to a &lt;code&gt;LiveData&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Flow&lt;/code&gt; is a better fit than &lt;code&gt;LiveData&lt;/code&gt; for all the other layers of an application like repositories or data sources, because it doesn’t depend on Android-specific lifecycles and is easier to test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you know the tradeoffs you’re willing to make if you still want to fully “go with the Flow” and eradicate LiveData from your Android UI layer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update (June 2022):&lt;/strong&gt; I wrote &lt;a href="https://dev.to/cbeyls/smarter-shared-kotlin-flows-41n0"&gt;a follow-up article&lt;/a&gt; describing a pattern that can be used to improve Kotlin Flow synchronization with the Lifecycle and make &lt;code&gt;SharedFlow&lt;/code&gt; as efficient as &lt;code&gt;LiveData&lt;/code&gt; in ViewModels.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Are you concerned about performance and experienced similar issues? Did you find other ways to work around them? If so, feel free to post a message in the comments section and as always, please share or subscribe if you enjoyed reading this long article.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>androiddev</category>
      <category>android</category>
      <category>flow</category>
    </item>
    <item>
      <title>Fixing RecyclerView nested scrolling in opposite direction</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Wed, 25 Mar 2020 23:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/fixing-recyclerview-nested-scrolling-in-opposite-direction-2l77</link>
      <guid>https://dev.to/cbeyls/fixing-recyclerview-nested-scrolling-in-opposite-direction-2l77</guid>
      <description>&lt;p&gt;&lt;code&gt;RecyclerView&lt;/code&gt; is one of the main building blocks of Android user interfaces today. It’s more capable and flexible than its &lt;code&gt;ListView&lt;/code&gt; predecessor but this also leads to more complexity and new problems.&lt;/p&gt;

&lt;p&gt;One core feature of &lt;code&gt;RecyclerView&lt;/code&gt; is the externalization of its layout engine to components called &lt;code&gt;LayoutManager&lt;/code&gt;s, which are no longer limited to vertical scrolling only. Most implementations allow to choose between horizontal and vertical scrolling and a &lt;code&gt;LayoutManager&lt;/code&gt; could technically support &lt;em&gt;both&lt;/em&gt; at the same time.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RecyclerView&lt;/code&gt; also supports &lt;strong&gt;nested scrolling&lt;/strong&gt; by implementing the &lt;a href="https://developer.android.com/reference/androidx/core/view/NestedScrollingChild3" rel="noopener noreferrer"&gt;&lt;code&gt;NestedScrollingChild3&lt;/code&gt;&lt;/a&gt; interface, which means it can cooperate with a parent view implementing &lt;a href="https://developer.android.com/reference/androidx/core/view/NestedScrollingParent3" rel="noopener noreferrer"&gt;&lt;code&gt;NestedScrollingParent3&lt;/code&gt;&lt;/a&gt; when both are configured to scroll in the same direction. In a nutshell, the scrolling child intercepts a scroll event and initiates a nested scroll in cooperation with the scrolling parent. Depending on its internal logic, the parent optionally consumes the scroll before or after the child, until they both reach their available scroll distance. A single scroll event may be consumed by both the parent and child with a seamless transition. For example, this mechanism is used when a &lt;code&gt;RecyclerView&lt;/code&gt; is placed inside a &lt;a href="https://developer.android.com/reference/androidx/coordinatorlayout/widget/CoordinatorLayout" rel="noopener noreferrer"&gt;&lt;code&gt;CoordinatorLayout&lt;/code&gt;&lt;/a&gt; next to an app bar which will automatically slide up or collapse when a scroll gesture is initiated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note that &lt;code&gt;RecyclerView&lt;/code&gt; doesn’t implement &lt;a href="https://developer.android.com/reference/androidx/core/view/NestedScrollingParent3" rel="noopener noreferrer"&gt;&lt;code&gt;NestedScrollingParent3&lt;/code&gt;&lt;/a&gt;, so using a scrollable child inside a &lt;code&gt;RecyclerView&lt;/code&gt; which scrolls in the same direction is not supported. However, Google currently provides &lt;a href="https://developer.android.com/develop/ui/views/animations/vp2-migration#nested-scrollables" rel="noopener noreferrer"&gt;a workaround&lt;/a&gt; to implement nested scrolling in a &lt;strong&gt;&lt;code&gt;ViewPager2&lt;/code&gt;&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;What about nested scrolling in the &lt;strong&gt;opposite direction&lt;/strong&gt;? This should be supported out-of-the-box, since a vertical scrolling view is not supposed to intercept horizontal gestures and vice versa. In practice this works well with the legacy &lt;code&gt;ViewPager&lt;/code&gt; which only scrolls horizontally, ignoring vertical gestures.&lt;/p&gt;

&lt;p&gt;But there is a problem with &lt;code&gt;RecyclerView&lt;/code&gt;, and by extension &lt;code&gt;ViewPager2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Suppose we have a &lt;code&gt;RecyclerView&lt;/code&gt; with a &lt;strong&gt;vertical&lt;/strong&gt; &lt;code&gt;LinearLayoutManager&lt;/code&gt; and each item of this vertical list consists of a &lt;code&gt;RecyclerView&lt;/code&gt; with an &lt;strong&gt;horizontal&lt;/strong&gt; &lt;code&gt;LinearLayoutManager&lt;/code&gt;. This kind of layout with scrollable horizontal items inside a vertical list is commonly found in Netflix-like video streaming apps with scrollable movie posters inside sections, or the Google Play Store app.&lt;/p&gt;

&lt;p&gt;Notice that attempting to scroll the nested horizontal &lt;code&gt;RecyclerView&lt;/code&gt;s often ends up with unexpected results.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fascp0fczk541cj5kx40p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fascp0fczk541cj5kx40p.gif" alt="Horizontal scroll is expected, but vertical scroll kicks in instead." width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;
Horizontal scroll is expected, but vertical scroll kicks in instead.



&lt;p&gt;Many times, even though an horizontal gesture is performed on a child &lt;code&gt;RecyclerView&lt;/code&gt;, the parent &lt;code&gt;RecyclerView&lt;/code&gt; kicks in and intercepts the touch event instead of the child &lt;code&gt;RecyclerView&lt;/code&gt;, resulting in a small vertical scroll instead of an horizontal scroll. This actually happens &lt;strong&gt;when the scroll gesture is not perfectly horizontal&lt;/strong&gt;. It’s actually &lt;strong&gt;diagonal&lt;/strong&gt;, even if you can see that the vertical distance of the gesture is small compared to its horizontal distance and its intent was clearly horizontal.&lt;/p&gt;

&lt;p&gt;Most of the time when using our phones, we are actually performing such imprecise diagonal gestures because we expect the system to understand our intent based on the current context. And it usually does it pretty well, but not in this particular case where only a perfectly horizontal gesture will be recognized. It harms the user experience. &lt;strong&gt;That’s why I consider it a bug.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing ViewPager2
&lt;/h2&gt;

&lt;p&gt;At this point you may think that nested &lt;code&gt;RecyclerView&lt;/code&gt;s are rare so the severity of this issue is low.&lt;/p&gt;

&lt;p&gt;But it turns out that the new &lt;code&gt;ViewPager2&lt;/code&gt; layout, which officially replaces the legacy &lt;code&gt;ViewPager&lt;/code&gt;, uses a &lt;code&gt;RecyclerView&lt;/code&gt; internally. Horizontal pagers are present in almost every app I’m aware of, and the pages often contain a vertical &lt;code&gt;RecyclerView&lt;/code&gt; or some form of &lt;code&gt;ScrollView&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s what happens when you try to scroll a vertical &lt;code&gt;RecyclerView&lt;/code&gt; inside a parent horizontal &lt;code&gt;ViewPager2&lt;/code&gt; (which internally uses a &lt;code&gt;RecyclerView&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjfobfdm52g232sksplag.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjfobfdm52g232sksplag.gif" alt="Vertical scroll is expected, but the horizontal ViewPager2 reacts instead." width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;
Vertical scroll is expected, but the horizontal ViewPager2 reacts instead.



&lt;p&gt;This time the &lt;code&gt;ViewPager2&lt;/code&gt; takes over and intercepts the gesture, &lt;strong&gt;unless it’s perfectly vertical&lt;/strong&gt; (which is difficult to achieve). The result is the same with any kind of &lt;code&gt;ViewPager2&lt;/code&gt; adapter, including &lt;code&gt;FragmentStateAdapter&lt;/code&gt;. In my opinion this makes &lt;code&gt;ViewPager2&lt;/code&gt;, in its current state, practically unusable compared to the legacy &lt;code&gt;ViewPager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same annoying behavior occurs when the pages contain a &lt;code&gt;ScrollView&lt;/code&gt; or a &lt;code&gt;NestedScrollView&lt;/code&gt;, hinting at which component is causing these problems: &lt;strong&gt;the parent &lt;code&gt;RecyclerView&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cause
&lt;/h2&gt;

&lt;p&gt;Rather than giving up and reverting to &lt;code&gt;ViewPager&lt;/code&gt;, I decided to investigate by debugging and looking at the source code of &lt;code&gt;RecyclerView&lt;/code&gt;. The culprit is the code responsible for initiating a scroll inside the &lt;code&gt;onInterceptTouchEvent()&lt;/code&gt; method (taken from version 1.1.0 of the RecyclerView library):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;canScrollHorizontally&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mLayout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;canScrollHorizontally&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;canScrollVertically&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mLayout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;canScrollVertically&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;MotionEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACTION_MOVE&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getX&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5f&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getY&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5f&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mScrollState&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;SCROLL_STATE_DRAGGING&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mInitialTouchX&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mInitialTouchY&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;startScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canScrollHorizontally&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mTouchSlop&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;mLastTouchX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;startScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canScrollVertically&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dy&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mTouchSlop&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;mLastTouchY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;startScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startScroll&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;setScrollState&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SCROLL_STATE_DRAGGING&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mScrollState&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;SCROLL_STATE_DRAGGING&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;dx&lt;/code&gt; and &lt;code&gt;dy&lt;/code&gt; are respectively the horizontal and vertical distances the finger has travelled the on screen since it started touching it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;RecyclerView&lt;/code&gt; will switch to &lt;strong&gt;&lt;code&gt;SCROLL_STATE_DRAGGING&lt;/code&gt;&lt;/strong&gt; mode and the method will return &lt;strong&gt;&lt;code&gt;true&lt;/code&gt;&lt;/strong&gt; to intercept the gesture (preventing the child views from detecting it) as soon as the &lt;em&gt;touch slop&lt;/em&gt; is reached in its scrolling direction. The touch slop is the minimal distance a finger must move on the screen before a touch event is considered as an actual drag gesture and not a tap. When a gesture is &lt;strong&gt;perfectly horizontal&lt;/strong&gt;, the vertical touch slop is not reached and a vertical &lt;code&gt;RecyclerView&lt;/code&gt; will not interfere. But if it’s not perfect and rather diagonal, then a vertical &lt;code&gt;RecyclerView&lt;/code&gt; will consider it as a vertical gesture nonetheless and start a vertical scroll.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In summary, the problem is that when the &lt;code&gt;RecyclerView&lt;/code&gt; is configured to scroll in a single direction as it’s usually the case, it doesn’t test if the global shape of the gesture is more horizontal (&lt;code&gt;abs(dx) &amp;gt; abs(dy)&lt;/code&gt;) or vertical (&lt;code&gt;abs(dy) &amp;gt; abs(dx)&lt;/code&gt;) before deciding to intercept it, potentially conflicting with a child view scrolling in the opposite direction.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A better drag gesture detection code would be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canScrollHorizontally&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mTouchSlop&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canScrollVertically&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dy&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mLastTouchX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;startScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canScrollVertically&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dy&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mTouchSlop&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canScrollHorizontally&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dy&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;abs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mLastTouchY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;startScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With this code, the behavior will be the same as before if the &lt;code&gt;RecyclerView&lt;/code&gt; scrolls in both directions, but will check the gesture direction before intercepting it if the &lt;code&gt;RecyclerView&lt;/code&gt; scrolls in a single direction.&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;Ideally the above code change would be integrated directly into the RecyclerView library. One of the motivations behind this article is to raise the attention of developers working at Google, in the hopes that they will eventually release a fixed version.&lt;/p&gt;

&lt;p&gt;In the meantime, which options are available to work around this issue today?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A first attempt would be to extend the &lt;code&gt;RecyclerView&lt;/code&gt; class and override the &lt;code&gt;onInterceptTouchEvent()&lt;/code&gt; method.&lt;/strong&gt; This is not easy because the original code of this method is accessing private fields which are not available to child classes, so it can’t just be copy-pasted and updated. Instead, you have to call the &lt;code&gt;super.onInterceptTouchEvent()&lt;/code&gt; method, then duplicate some of the detection logic and tweak it in order to cancel the scroll and finally return &lt;strong&gt;&lt;code&gt;false&lt;/code&gt;&lt;/strong&gt; instead of &lt;strong&gt;&lt;code&gt;true&lt;/code&gt;&lt;/strong&gt; for the cases discussed earlier. Next, you would have to change all your layout files to use that new class. But then, what about &lt;code&gt;ViewPager2&lt;/code&gt;? It will still use the original &lt;code&gt;RecyclerView&lt;/code&gt; internally instead of the fixed one, which means you’d have to create and maintain a custom version of &lt;code&gt;ViewPager2&lt;/code&gt; as well! &lt;strong&gt;This turns out to be quite impractical.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is a better way. As mentioned in the introduction, &lt;code&gt;RecyclerView&lt;/code&gt; is flexible and features a modular architecture enabling the usage of extensions. It turns out that such an extension can be created to customize the behavior of the scroll gesture detection. In detail, the extension will have to use a combination of 2 &lt;code&gt;RecyclerView&lt;/code&gt; APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;OnItemTouchListener&lt;/code&gt; to be registered on the &lt;code&gt;RecyclerView&lt;/code&gt;, where the updated gesture detection code (based on the original code of RecyclerView) will be implemented by overriding &lt;code&gt;onInterceptTouchEvent()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;OnScrollListener&lt;/code&gt; to be registered on the &lt;code&gt;RecyclerView&lt;/code&gt; as well, whose role is to detect transitions from &lt;strong&gt;&lt;code&gt;SCROLL_STATE_IDLE&lt;/code&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;code&gt;SCROLL_STATE_DRAGGING&lt;/code&gt;&lt;/strong&gt; and revert back to &lt;strong&gt;&lt;code&gt;SCROLL_STATE_IDLE&lt;/code&gt;&lt;/strong&gt; if required (depending on the data provided by the updated gesture detection code). After reverting back, &lt;code&gt;RecyclerView.onInterceptTouchEvent()&lt;/code&gt; will now return &lt;strong&gt;&lt;code&gt;false&lt;/code&gt;&lt;/strong&gt; and the gesture will not be captured.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the full code, provided as a single &lt;strong&gt;Kotlin extension function&lt;/strong&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;For &lt;strong&gt;&lt;code&gt;ViewPager2&lt;/code&gt;&lt;/strong&gt;, an additional extension property has to be created in order to make its internal &lt;code&gt;RecyclerView&lt;/code&gt; public:&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;import&lt;/span&gt; &lt;span class="nn"&gt;androidx.core.view.get&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;androidx.viewpager2.widget.ViewPager2&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;ViewPager2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recyclerView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecyclerView&lt;/span&gt;
    &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&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="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;RecyclerView&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to enable the fix for a &lt;code&gt;ViewPager2&lt;/code&gt; instance, one would call:&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;pager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewPager2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recyclerView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enforceSingleScrollDirection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mission accomplished. Now the parent &lt;code&gt;RecyclerView&lt;/code&gt; and &lt;code&gt;ViewPager2&lt;/code&gt; will react properly to diagonal gestures and the app users can enjoy easier nested scrolling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjb4f07xwbb3g1gthw993.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjb4f07xwbb3g1gthw993.gif" alt="Horizontal Recyclerviews reacting properly inside a vertical Recyclerview" width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6bghm8jmyzi7amdjcxmg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6bghm8jmyzi7amdjcxmg.gif" alt="Vertical Recyclerview reacting properly inside an horizontal ViewPager2" width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;As an early adopter of the first stable version of &lt;code&gt;ViewPager2&lt;/code&gt;, I was surprised to hardly see anyone raising concerns about the usability of this new widget in nested lists scenarios, compared to its predecessor. Issues with nested scrolling have been present since the first release of &lt;code&gt;RecyclerView&lt;/code&gt; but don’t seem to get much attention. At least we now have a simple pluggable fix which doesn’t involve subclassing, &lt;strong&gt;altough it should still be considered as a hack and may break in future versions of the library&lt;/strong&gt;. I created &lt;a href="https://issuetracker.google.com/issues/168716647" rel="noopener noreferrer"&gt;an issue for this on the RecyclerView issue tracker&lt;/a&gt; so you can follow the progress of a fix in the library itself.&lt;/p&gt;

&lt;p&gt;Thank you for reading this and please share and comment to help feeding the debate.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Special thanks to &lt;a href="https://medium.com/@okmanideep" rel="noopener noreferrer"&gt;Manideep Polireddi&lt;/a&gt; who was the first person to document this issue.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>androiddev</category>
      <category>recyclerview</category>
      <category>android</category>
    </item>
    <item>
      <title>A study of the Parcelize feature from Kotlin Android Extensions</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Mon, 18 Nov 2019 23:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/a-study-of-the-parcelize-feature-from-kotlin-android-extensions-53f0</link>
      <guid>https://dev.to/cbeyls/a-study-of-the-parcelize-feature-from-kotlin-android-extensions-53f0</guid>
      <description>&lt;p&gt;Two years ago, I &lt;a href="https://dev.to/cbeyls/reducing-parcelable-boilerplate-code-using-kotlin-j4c"&gt;wrote&lt;/a&gt; about how you can leverage features of the Kotlin programming language to manually write your Android &lt;a href="https://developer.android.com/reference/android/os/Parcelable.html" rel="noopener noreferrer"&gt;&lt;code&gt;Parcelable&lt;/code&gt;&lt;/a&gt; implementations in the most concise and readable way. Does it mean that I always prefer writing this code manually rather than letting a library or tool generate it for me? Of course not: like most developers, I believe that &lt;strong&gt;the best code is the code you don’t have to write&lt;/strong&gt;. But I expect the tools I use to meet my quality standards.&lt;/p&gt;

&lt;p&gt;That’s why I tend to be conservative about the dependencies I add to my projects and will always favor official libraries from Jetbrains or Google over third-party solutions. Things have changed for the better since I wrote the previous article: with the release of &lt;strong&gt;Kotlin 1.3.40&lt;/strong&gt;, &lt;code&gt;@Parcelize&lt;/code&gt; is now a &lt;em&gt;stable&lt;/em&gt; feature provided by the Parcelize Gradle plugin (formerly known as Kotlin Android Extensions). And since &lt;strong&gt;version 1.3.60&lt;/strong&gt;, the Android Studio plugin also properly recognizes the feature as non-experimental so it can finally be considered as &lt;strong&gt;production-ready&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I previously enumerated a list of some of the negative aspects of third-party Parcelable code generation libraries compared to manual implementation. Here’s why I believe &lt;code&gt;@Parcelize&lt;/code&gt; stands out from the rest in regard to that list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s an official plugin made by JetBrains with the collaboration of Google and is guaranteed to be well supported in the future&lt;/li&gt;
&lt;li&gt;The generated code of &lt;code&gt;@Parcelize&lt;/code&gt; is very efficient (as we’ll discover further in this article)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;CREATOR&lt;/code&gt; field doesn’t have to be declared at all, along with that easy-to-forget &lt;code&gt;@JvmField&lt;/code&gt; annotation&lt;/li&gt;
&lt;li&gt;Thanks to the &lt;code&gt;Parceler&lt;/code&gt; interface, it is possible to write simple plugins to handle unsupported types or override the default implementation&lt;/li&gt;
&lt;li&gt;No extra classes are created by the plugin. All the generated code is embedded in the annotated class so the app will behave exactly as if you wrote the code yourself&lt;/li&gt;
&lt;li&gt;There is no runtime library overhead and zero extra methods are added to your app.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Project setup
&lt;/h2&gt;

&lt;p&gt;First, you should upgrade your Kotlin Gradle plugins and Android Studio plugin to version &lt;strong&gt;1.3.60&lt;/strong&gt; or more recent.&lt;/p&gt;

&lt;h3&gt;
  
  
  For Kotlin 1.3.60 to 1.4.10
&lt;/h3&gt;

&lt;p&gt;To enable the “Parcelable implementation generator” feature, you have to &lt;strong&gt;enable the Kotlin Android Extensions Gradle plugin&lt;/strong&gt; in your project by simply declaring it at the top of your module’s &lt;strong&gt;&lt;code&gt;build.gradle&lt;/code&gt;&lt;/strong&gt; file, just after the &lt;strong&gt;&lt;code&gt;kotlin-android&lt;/code&gt;&lt;/strong&gt; plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'com.android.application'&lt;/span&gt;
&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'kotlin-android'&lt;/span&gt;
&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'kotlin-android-extensions'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By using the newer version of the plugin, it’s not necessary anymore to turn on experimental mode to be able to use the &lt;code&gt;@Parcelize&lt;/code&gt; feature or for the IDE to detect it as available.&lt;/p&gt;

&lt;p&gt;However, I’m not a big fan of the other features provided by this plugin like the &lt;em&gt;View binding and caching&lt;/em&gt;. By default, this will scan your layouts and generate static properties for every View with an id, as well as adding a hidden View cache in your Activities and Fragments. I don’t want it. Fortunately, there is a way to &lt;strong&gt;enable Parcelize while disabling other features of the plugin&lt;/strong&gt;. Add this extra section to the same &lt;strong&gt;&lt;code&gt;build.gradle&lt;/code&gt;&lt;/strong&gt; file, below the &lt;code&gt;android&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;androidExtensions&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"parcelize"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Since Kotlin 1.4.20
&lt;/h3&gt;

&lt;p&gt;All other features of the Kotlin Android Extensions Gradle plugin &lt;a href="https://android-developers.googleblog.com/2020/11/the-future-of-kotlin-android-extensions.html" rel="noopener noreferrer"&gt;have been deprecated since Kotlin 1.4.20&lt;/a&gt; and &lt;strong&gt;Parcelize has moved to its own Gradle plugin&lt;/strong&gt;. Enable it by declaring it at the top of your module’s &lt;strong&gt;&lt;code&gt;build.gradle&lt;/code&gt;&lt;/strong&gt; file, just after the &lt;strong&gt;&lt;code&gt;kotlin-android&lt;/code&gt;&lt;/strong&gt; plugin:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'com.android.application'&lt;/span&gt;
&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'kotlin-android'&lt;/span&gt;
&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'kotlin-parcelize'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We’re all set to use the &lt;code&gt;@Parcelize&lt;/code&gt; annotation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Just add the &lt;code&gt;@Parcelize&lt;/code&gt; annotation to a class implementing the &lt;code&gt;Parcelable&lt;/code&gt; interface and the Parcelable implementation will be generated automatically.&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is the same example as in the previous article, in just 2 lines of code.&lt;/p&gt;

&lt;p&gt;The class can be a &lt;code&gt;data class&lt;/code&gt; but it’s optional. All properties to serialize have to be declared in the &lt;strong&gt;primary constructor&lt;/strong&gt;, and like a &lt;code&gt;data class&lt;/code&gt; all parameters of the primary constructor need to be properties. They can be &lt;code&gt;val&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt; or &lt;code&gt;public&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The main limitation of the feature is that it is not allowed to annotate &lt;code&gt;abstract&lt;/code&gt; or &lt;code&gt;sealed&lt;/code&gt; classes. To make them implement the &lt;code&gt;Parcelable&lt;/code&gt; interface you can annotate each of their child classes instead. We’ll go further into details with concrete examples in a following chapter.&lt;/p&gt;
&lt;h2&gt;
  
  
  Analyzing the generated code
&lt;/h2&gt;

&lt;p&gt;This looks fine so far, but what about the quality of the generated code? Is the implementation as efficient as it could be? Let’s find out.&lt;/p&gt;

&lt;p&gt;We’re going to use the &lt;strong&gt;Kotlin Bytecode inspector&lt;/strong&gt; on the annotated class and decompile it back to Java to reveal the code under the hood.&lt;/p&gt;
&lt;h3&gt;
  
  
  Basic types
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Basic&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;aByte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Byte&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;aShort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Short&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;anInt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&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;aLong&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&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;aFloat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&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;aDouble&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&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;aBoolean&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&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;aString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The following code will be generated:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeByte&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aByte&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aShort&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;anInt&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeLong&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aLong&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeFloat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aFloat&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aDouble&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aBoolean&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aString&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For basic types like primitives and &lt;code&gt;String&lt;/code&gt;, we see that the proper dedicated methods from the &lt;code&gt;Parcel&lt;/code&gt; class are used as expected. Notice that the &lt;code&gt;Boolean&lt;/code&gt; value is written as an &lt;code&gt;Int&lt;/code&gt;. This is because at the Java bytecode level, a boolean is represented as a primitive integer whose value is either 0 or 1. The programming language hides this abstraction. Also, the &lt;code&gt;Short&lt;/code&gt; value is written as an &lt;code&gt;Int&lt;/code&gt; as well, because the &lt;code&gt;Parcel&lt;/code&gt; API doesn’t provide a way to serialize &lt;code&gt;Short&lt;/code&gt; values so the next bigger integer type is used instead.&lt;/p&gt;

&lt;p&gt;The code which reads back the values looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Creator&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Parcelable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Creator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;newArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Basic&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Basic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readByte&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;short&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readInt&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readInt&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readLong&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readFloat&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readDouble&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readInt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Besides the above code, no additional constructor or method is added to the base class and all of the Parcelable deserialization code fits inside the &lt;code&gt;createFromParcel()&lt;/code&gt; method of the &lt;code&gt;Creator&lt;/code&gt; class. This guarantees that the number of methods in the application’s APK file will be as low as possible, which is always important.&lt;/p&gt;
&lt;h3&gt;
  
  
  Nullable types
&lt;/h3&gt;

&lt;p&gt;Here is another Kotlin sample with various types of nullable fields.&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NullableFields&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;aNullableInt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&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;aNullableFloat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&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;aNullableBoolean&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&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;aNullableString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The generated serialization code decompiles to this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;var10001&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aNullableInt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var10001&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var10001&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="nc"&gt;Float&lt;/span&gt; &lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aNullableFloat&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeFloat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aNullableBoolean&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var4&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aNullableString&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For nullable counterparts of primitive types, the plugin generates code which writes an extra integer before the value to indicate if it’s &lt;code&gt;null&lt;/code&gt; or not, which is just as efficient as a manual implementation. As for the &lt;code&gt;String?&lt;/code&gt; value, &lt;code&gt;Parcel.writeString()&lt;/code&gt; already properly handles null values so no integer is added to serialize this type.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Nullable fields are handled properly and efficiently for every type.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Nested Parcelables
&lt;/h3&gt;

&lt;p&gt;Let’s declare a &lt;code&gt;Parcelable&lt;/code&gt; class embedding a &lt;code&gt;Parcelable&lt;/code&gt; field.&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"String, val author: Person) : Parcelable"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Person&lt;/code&gt; is the class we defined earlier, which is also &lt;code&gt;Parcelable&lt;/code&gt;. Here is the representation of the serialization code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Interesting: the plugin generated a direct nested call to &lt;code&gt;writeToParcel()&lt;/code&gt;. This is equivalent to calling &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#writeTypedObject(T,%20int)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.writeTypedObject()&lt;/code&gt;&lt;/a&gt;. It’s very efficient because it allows skipping writing the class name of the nested type like &lt;code&gt;Parcel.writeParcelable()&lt;/code&gt; does. This information is normally used during deserialization in order to perform a small reflection lookup to retrieve the &lt;code&gt;CREATOR&lt;/code&gt; field corresponding to the correct subtype.&lt;/p&gt;

&lt;p&gt;But in this case the &lt;code&gt;CREATOR&lt;/code&gt; field to use is well-known and unique, because the &lt;code&gt;Person&lt;/code&gt; class is &lt;code&gt;final&lt;/code&gt;. That’s why the deserialization code looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CREATOR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createFromParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For non-final classes or interfaces, the Parcelize plugin will generate a call to &lt;code&gt;Parcel.writeParcelable()&lt;/code&gt; instead.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Classes are &lt;code&gt;final&lt;/code&gt; by default in Kotlin, allowing optimized nested serialization to be used in most cases. If you are including a Java &lt;code&gt;Parcelable&lt;/code&gt; class as a field of a Kotlin class annotated with &lt;code&gt;@Parcelize&lt;/code&gt;, declare the class as &lt;code&gt;final&lt;/code&gt; whenever possible to be able to benefit from the same optimization.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Enum classes
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;enum&lt;/code&gt; classes are supported out-of-the-box by the plugin.&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;enum&lt;/span&gt; &lt;span class="kd"&gt;class&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;ON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OFF&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PowerSwitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;state&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="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Serialization code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The enum value name is written as a &lt;code&gt;String&lt;/code&gt; and the deserialization code uses &lt;code&gt;Enum.valueOf(Class enumType, String name)&lt;/code&gt; to transform the name back to an enum value. This is definitely more efficient than using &lt;code&gt;writeSerializable()&lt;/code&gt; which must be avoided at all costs on Android for performance and efficiency reasons. Internally, the &lt;code&gt;Enum&lt;/code&gt; implementation uses a name cache to quickly retrieve an enum value from its name.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Another way of efficiently serializing an enum value would be to store its &lt;code&gt;ordinal()&lt;/code&gt; integer, &lt;del&gt;with the downside of having the values array cloned each time &lt;code&gt;EnumType.values()&lt;/code&gt; is called during deserialization&lt;/del&gt; and during deserialization reading the value back from the read-only cached &lt;code&gt;EnumType.entries&lt;/code&gt; collection generated by the Kotlin compiler since Kotlin 1.9.2 to avoid extra memory allocations. In summary, the code generated by the plugin is fine in terms of performance.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Bonus feature: make enum classes implement &lt;code&gt;Parcelable&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;You can actually annotate an &lt;code&gt;enum class&lt;/code&gt; itself if you make it implement &lt;code&gt;Parcelable&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="kd"&gt;class&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;Parcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OFF&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Unlike regular classes whose properties are serialized, the enum classes have their value name serialized so that the proper value instance is retrieved from memory on deserialization (since &lt;code&gt;enum&lt;/code&gt; values are singletons).&lt;/p&gt;

&lt;p&gt;This is particularly handy when you want to put an &lt;code&gt;enum&lt;/code&gt; value in a &lt;code&gt;Bundle&lt;/code&gt; (as an &lt;code&gt;Intent&lt;/code&gt; extra or &lt;code&gt;Fragment&lt;/code&gt; argument for example), without having to use &lt;code&gt;Bundle.putSerializable()&lt;/code&gt; which is slower and less efficient and without having to write your own helper methods for custom serialization. Now you can just write:&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;args&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Bundle&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="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;putParcelable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"state"&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;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Collections
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@Parcelize&lt;/code&gt; supports a wide range of collections by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All array types (&lt;code&gt;ShortArray&lt;/code&gt; is serialized as a series of &lt;code&gt;Int&lt;/code&gt; values because &lt;code&gt;Parcel&lt;/code&gt; doesn't support &lt;code&gt;Short&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;, &lt;code&gt;Map&lt;/code&gt; interfaces (mapped to &lt;code&gt;ArrayList&lt;/code&gt;, &lt;code&gt;LinkedHashSet&lt;/code&gt; and &lt;code&gt;LinkedHashMap&lt;/code&gt; respectively)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ArrayList&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt;, &lt;code&gt;SortedSet&lt;/code&gt;, &lt;code&gt;NavigableSet&lt;/code&gt;, &lt;code&gt;HashSet&lt;/code&gt;, &lt;code&gt;LinkedHashSet&lt;/code&gt;, &lt;code&gt;TreeSet&lt;/code&gt;, &lt;code&gt;SortedMap&lt;/code&gt;, &lt;code&gt;NavigableMap&lt;/code&gt;, &lt;code&gt;HashMap&lt;/code&gt;, &lt;code&gt;LinkedHashMap&lt;/code&gt;, &lt;code&gt;TreeMap&lt;/code&gt;, &lt;code&gt;ConcurrentHashMap&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Android-specific framework collections: &lt;code&gt;SparseArray&lt;/code&gt;, &lt;code&gt;SparseIntArray&lt;/code&gt;, &lt;code&gt;SparseLongArray&lt;/code&gt;, &lt;code&gt;SparseBooleanArray&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the following types: &lt;code&gt;ByteArray&lt;/code&gt;, &lt;code&gt;IntArray&lt;/code&gt;, &lt;code&gt;CharArray&lt;/code&gt;, &lt;code&gt;LongArray&lt;/code&gt;, &lt;code&gt;FloatArray&lt;/code&gt;, &lt;code&gt;DoubleArray&lt;/code&gt;, &lt;code&gt;BooleanArray&lt;/code&gt;, &lt;code&gt;Array&amp;lt;String&amp;gt;&lt;/code&gt;, &lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt;, &lt;code&gt;Array&amp;lt;Binder&amp;gt;&lt;/code&gt;, the generated code will simply call the dedicated optimized methods from the &lt;code&gt;Parcel&lt;/code&gt; API. For other array and collection types, things work differently.&lt;/p&gt;

&lt;p&gt;Here is an example of a class including a collection of objects implementing &lt;code&gt;Parcelable&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Library&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;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The bytecode inspector reveals that the generated code doesn’t use &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#writeTypedList(java.util.List%3CT%3E)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.writeTypedList()&lt;/code&gt;&lt;/a&gt; from the Parcel API but instead inlines the logic to handle the list directly in the body of the &lt;code&gt;writeToParcel()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;var10002&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;books&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var10002&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
   &lt;span class="nc"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;var10000&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;var10002&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

   &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var10000&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasNext&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;var10000&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Same goes for the deserialization code. This way of doing things actually has two benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It allows Parcelize to &lt;strong&gt;support more collection types&lt;/strong&gt; than the ones provided by the &lt;code&gt;Parcel&lt;/code&gt; collections API, without adding extra methods to the code.&lt;/li&gt;
&lt;li&gt;Serialization will be more efficient for many types compared to the &lt;code&gt;Parcel&lt;/code&gt; collections API implementation because the compiler plugin will always use the best serialization method for each value type in the collection. For example, serializing a &lt;code&gt;SparseArray&amp;lt;Book&amp;gt;&lt;/code&gt; (where &lt;code&gt;Book&lt;/code&gt; is a final class) using &lt;code&gt;Parcel.writeSparseArray()&lt;/code&gt; will result in &lt;code&gt;Parcel.writeValue()&lt;/code&gt; to be used to serialize the &lt;code&gt;Book&lt;/code&gt; type. This method is less efficient because for each value it will write an extra integer describing the value type (which is unnecessary because all values are of the same type in this case), then use &lt;code&gt;Parcel.writeParcelable()&lt;/code&gt; which is also less efficient than a nested call to &lt;code&gt;Book.writeToParcel()&lt;/code&gt; as we saw earlier. In comparison, the Parcelize plugin will just generate a call to &lt;code&gt;Book.writeToParcel()&lt;/code&gt; for each value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that &lt;code&gt;ArrayMap&lt;/code&gt;, &lt;code&gt;ArraySet&lt;/code&gt;, &lt;code&gt;LongSparseArray&lt;/code&gt; from the Android framework are not supported by default, as well as all the unbundled collection classes provided by the Jetpack libraries: &lt;code&gt;ArrayMap&lt;/code&gt;, &lt;code&gt;ArraySet&lt;/code&gt;, &lt;code&gt;LongSparseArray&lt;/code&gt;, &lt;code&gt;SimpleArrayMap&lt;/code&gt;, &lt;code&gt;SparseArrayCompat&lt;/code&gt;. Consider using &lt;code&gt;SparseArray&lt;/code&gt; instead of &lt;code&gt;SparseArrayCompat&lt;/code&gt;, and write your own custom serializer for the other types if you need them.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code&gt;ArrayDeque&lt;/code&gt;, &lt;code&gt;EnumMap&lt;/code&gt; and &lt;code&gt;EnumSet&lt;/code&gt; may &lt;em&gt;look&lt;/em&gt; like they are supported, but it’s only because they implement the &lt;code&gt;Serializable&lt;/code&gt; interface and the generated code will just fall back to using &lt;code&gt;Parcel.writeSerializable()&lt;/code&gt; which is slow and inefficient. Therefore it’s highly recommended to either use more generic collection types like &lt;code&gt;Set&amp;lt;Enum&amp;gt;&lt;/code&gt; or write your own custom serializer, as we’ll see in the next chapter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When including collections in your &lt;code&gt;Parcelable&lt;/code&gt; objects, make sure their type is properly supported by the plugin or a custom serializer, especially when it implements the &lt;code&gt;Serializable&lt;/code&gt; interface.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60palhoxkofig6uozvz0.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60palhoxkofig6uozvz0.webp" alt="Cat inside a box" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Custom types serializers
&lt;/h2&gt;

&lt;p&gt;The Parcelize plugin also provides support for the remaining types that are part of the &lt;code&gt;Parcel&lt;/code&gt; API: &lt;code&gt;CharSequence&lt;/code&gt;, &lt;code&gt;Exception&lt;/code&gt; (&lt;a href="https://developer.android.com/reference/android/os/Parcel.html#writeException(java.lang.Exception)" rel="noopener noreferrer"&gt;which only supports a few types of Exceptions&lt;/a&gt;), &lt;code&gt;Size&lt;/code&gt;, &lt;code&gt;SizeF&lt;/code&gt;, &lt;code&gt;Bundle&lt;/code&gt;, &lt;code&gt;IBinder&lt;/code&gt;, &lt;code&gt;IInterface&lt;/code&gt; and &lt;code&gt;FileDescriptor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For all other types, it will default to using Parcel.writeSerializable() if the type implements Serializable (which — again — is bad for performance and produces a large amount of data, so must be avoided). If it doesn’t implement Serializable, a Lint warning will be shown and Parcel.writeValue() will be used instead, ultimately failing at runtime.&lt;/p&gt;

&lt;p&gt;To avoid both of the above cases, &lt;strong&gt;you should provide your own custom type serializer implementation&lt;/strong&gt; in the form of an &lt;code&gt;object&lt;/code&gt; implementing the &lt;code&gt;Parceler&lt;/code&gt; interface. Here’s a simple example for the &lt;code&gt;Date&lt;/code&gt; type:&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;object&lt;/span&gt; &lt;span class="nc"&gt;DateParceler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Date&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readLong&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="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&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, in order to make the plugin use that &lt;code&gt;Parceler&lt;/code&gt; implementation to serialize and deserialize properties using the &lt;code&gt;Date&lt;/code&gt; type, you need to add an extra annotation to your &lt;code&gt;Parcelable&lt;/code&gt; objects. You can either annotate the type of a property with &lt;code&gt;@WriteWith&amp;lt;ParcelerType&amp;gt;&lt;/code&gt;, or annotate the property or the whole class with &lt;code&gt;@TypeParceler&amp;lt;PropertyType, ParcelerType&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Annotating the Parcelable class&lt;/strong&gt; allows to group annotations together and avoid repetition, especially if you have many properties of the same type for which you want a custom serializer.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="nd"&gt;@TypeParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Session&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Date&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;endTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Annotating the property type&lt;/strong&gt; avoids any ambiguity regarding which implementation is going to be used to serialize a property. If there is a mismatch between the annotation and the type, a Lint warning will be shown in the IDE (but it won’t prevent compilation).
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Session&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nd"&gt;@WriteWith&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Date&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;endTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nd"&gt;@WriteWith&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let’s have a look at the generated code to check that the custom &lt;code&gt;Parceler&lt;/code&gt; implementation is being used in place of &lt;code&gt;writeSerializable()&lt;/code&gt; for the dates:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INSTANCE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INSTANCE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Handling nullable custom types
&lt;/h3&gt;

&lt;p&gt;Even though Parcelize provides support for serializing the nullable variant of all built-in types, it doesn’t add automatic support for the nullable variant of a custom type based on its non-null custom type &lt;code&gt;Parceler&lt;/code&gt;. This means that if you provide a &lt;code&gt;Parceler&lt;/code&gt; implementation for the &lt;code&gt;Date&lt;/code&gt; type, it won’t support &lt;code&gt;Date?&lt;/code&gt; properties automatically unless you add another annotation for the &lt;code&gt;Date?&lt;/code&gt; type as well.&lt;/p&gt;

&lt;p&gt;We can verify this by making the &lt;code&gt;endTime&lt;/code&gt; property nullable in our class…&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="nd"&gt;@TypeParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Session&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Date&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;endTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;… and then checking the generated code again:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INSTANCE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeSerializable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Indeed, &lt;code&gt;DateParceler&lt;/code&gt; is not used for the &lt;code&gt;endTime&lt;/code&gt; property. To fix this, another &lt;code&gt;@TypeParceler&lt;/code&gt; (or &lt;code&gt;@WriteWith&lt;/code&gt;) annotation needs to be added for the nullable &lt;code&gt;Date?&lt;/code&gt; type and the &lt;code&gt;Parceler&lt;/code&gt; implementation needs to properly handle nullable values as well.&lt;/p&gt;

&lt;p&gt;Fortunately, it’s not needed to provide two separate &lt;code&gt;Parceler&lt;/code&gt; implementations for nullable and non-null types: you can use a single one designed for nullable types to handle non-null types as well.&lt;/p&gt;

&lt;p&gt;Here is a sample collection of &lt;code&gt;Parceler&lt;/code&gt; implementations which are able to serialize and deserialize nullable and non-null variants of &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;BigInteger&lt;/code&gt; and &lt;code&gt;BigDecimal&lt;/code&gt; types.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When creating a custom &lt;code&gt;Parceler&lt;/code&gt; implementation, &lt;strong&gt;prefer declaring the nullable variant of the type&lt;/strong&gt; to be able to use it for both nullable and non-null properties.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Going back to our example, we can now use the revised &lt;code&gt;DateParceler&lt;/code&gt; implementation to handle nullable and non-null dates by adding annotations for both types:&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="nd"&gt;@TypeParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nd"&gt;@TypeParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Session&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Date&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;endTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we can confirm that the generated code now uses the custom type serializer for both date properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INSTANCE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startTime&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="nc"&gt;DateParceler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INSTANCE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Add annotations &lt;strong&gt;targeting the correct type variant&lt;/strong&gt; (nullable or non-null) &lt;strong&gt;for each property type requiring a custom serializer&lt;/strong&gt; in the primary constructor of the &lt;code&gt;Parcelable&lt;/code&gt; class. An annotation targeting a non-null type will be ignored for a nullable type, and vice-versa.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Handling generic custom types
&lt;/h3&gt;

&lt;p&gt;One limitation of custom &lt;code&gt;Parceler&lt;/code&gt; implementations is that they are required to be &lt;code&gt;object&lt;/code&gt; singletons. Which means they can’t be passed extra arguments through a constructor: a separate &lt;code&gt;object&lt;/code&gt; needs to be declared for each variation of the serialization algorithm.&lt;/p&gt;

&lt;p&gt;But you can work around that limitation and avoid duplicating code by creating reusable utility functions and/or parent classes to be used by these &lt;code&gt;object&lt;/code&gt; instances.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let’s illustrate this with an example&lt;/em&gt; by creating a &lt;code&gt;Parceler&lt;/code&gt; implementation for &lt;code&gt;EnumSet&amp;lt;E&amp;gt;&lt;/code&gt;. The concrete &lt;code&gt;Enum&lt;/code&gt; class is actually needed to be able to instantiate an &lt;code&gt;EnumSet&lt;/code&gt; and populate its values during deserialization. We would like to be able to pass that &lt;code&gt;Class&lt;/code&gt; as argument to the &lt;code&gt;Parceler&lt;/code&gt; at deserialization time but we can’t do it directly. Instead, it can be passed as constructor argument of a reusable &lt;code&gt;Parceler&lt;/code&gt; implementation:&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;open&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EnumSetParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;E&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;E&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;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;elementType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;E&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EnumSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;E&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;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;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elementType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enumConstants&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;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;EnumSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;E&lt;/span&gt;&lt;span class="p"&gt;&amp;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;set&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EnumSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;noneOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elementType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readInt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readInt&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;set&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;EnumSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;E&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;in&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="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeInt&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="n"&gt;ordinal&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;That single &lt;code&gt;open class&lt;/code&gt; can then be used as parent for multiple &lt;code&gt;object&lt;/code&gt; instances, one for each concrete &lt;code&gt;EnumSet&amp;lt;E&amp;gt;&lt;/code&gt; type that needs to be serialized using Parcelize:&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;object&lt;/span&gt; &lt;span class="nc"&gt;StateEnumSetParceler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EnumSetParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&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="nc"&gt;State&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;CategoryEnumSetParceler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EnumSetParceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We end up with a collection of objects that can be used to serialize variants of the same type, without the need to duplicate logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing generated CREATOR fields from Kotlin code
&lt;/h3&gt;

&lt;p&gt;When writing custom &lt;code&gt;Parcel&lt;/code&gt; deserialization code, for example by implementing a &lt;code&gt;Parceler&lt;/code&gt; object, sometimes you need to reference the static &lt;code&gt;CREATOR&lt;/code&gt; field of &lt;code&gt;Parcelable&lt;/code&gt; classes. It’s useful to create an object instance for a concrete type without relying on reflection, and is used among others by &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#createTypedArrayList(android.os.Parcelable.Creator%3CT%3E)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.createTypedArrayList()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#readTypedObject(android.os.Parcelable.Creator%3CT%3E)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.readTypedObject()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But sadly you’ll notice that the static &lt;code&gt;CREATOR&lt;/code&gt; fields generated by Parcelize are not visible from Kotlin code located in the same module. This is because these fields are added to the classes annotated with &lt;code&gt;@Parcelize&lt;/code&gt; at a later stage of the Kotlin compilation process, which means they don’t exist yet when the compiler attempts to resolve references amongst Kotlin files at the beginning of compilation. &lt;a href="https://github.com/JetBrains/kotlin/pull/4575" rel="noopener noreferrer"&gt;This issue is known since 2017&lt;/a&gt; &lt;del&gt;and no fix seems to be planned so far, which is a bit surprising for a feature that took years to be called “production-ready”&lt;/del&gt;. &lt;strong&gt;Update:&lt;/strong&gt; a solution is finally provided starting with Kotlin 1.6.20 (April 2022). You should use the specially optimized &lt;code&gt;parcelableCreator()&lt;/code&gt; function to reference the generated &lt;code&gt;CREATOR&lt;/code&gt; field of a &lt;code&gt;Parcelable&lt;/code&gt; class. For example:&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;object&lt;/span&gt; &lt;span class="nc"&gt;ExampleAParceler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parceler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ExampleA&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ExampleA&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;b&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parcelableCreator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ExampleB&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;createFromParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ExampleA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&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="nc"&gt;ExampleA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&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;Calls to the &lt;code&gt;parcelableCreator()&lt;/code&gt; function will be optimized during compilation and replaced with a direct access to the &lt;code&gt;CREATOR&lt;/code&gt; field for concrete types so no reflection will be involved!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxmwn7akv02btuqa6k4rr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxmwn7akv02btuqa6k4rr.gif" alt="Sokoban puzzle" width="288" height="320"&gt;&lt;/a&gt;&lt;/p&gt;
Sokoban puzzle by &lt;a href="https://borgar.net/" rel="noopener noreferrer"&gt;Borgar Þorsteinsson&lt;/a&gt;. Under &lt;a href="https://creativecommons.org/licenses/by/3.0/" rel="noopener noreferrer"&gt;Creative Commons license&lt;/a&gt;



&lt;h2&gt;
  
  
  Dealing with class inheritance
&lt;/h2&gt;

&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; annotate &lt;code&gt;open&lt;/code&gt; classes with &lt;code&gt;@Parcelize&lt;/code&gt;. However, it’s not possible to also annotate child classes that inherit from these &lt;code&gt;open&lt;/code&gt; classes without duplicating all the serializable properties of their parent class. Let’s look at an example to have a better understanding of the problem:&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;

&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ElectronicBook&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;_title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;_author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Person&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;downloadSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to comply with the Parcelize restriction of having all primary constructor arguments declared as either &lt;code&gt;val&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt;, we end up redeclaring two unnecessary properties for &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;author&lt;/code&gt; which are already handled by the parent class. &lt;strong&gt;This works but is far from elegant, not to mention duplicating fields in an object is wasting memory&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you need to create a child class inheriting from an &lt;code&gt;open&lt;/code&gt; &lt;code&gt;Parcelable&lt;/code&gt; class, you should either write the Parcelable implementation of that child class manually, or refactor the parent class to make it &lt;code&gt;abstract&lt;/code&gt; or &lt;code&gt;sealed&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the case of the above example, the &lt;code&gt;Book&lt;/code&gt; class would be turned into an &lt;code&gt;abstract&lt;/code&gt; or &lt;code&gt;sealed&lt;/code&gt; class (or even an interface) with a new concrete child class &lt;code&gt;PaperBook&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parcelable abstract and sealed classes with common fields
&lt;/h3&gt;

&lt;p&gt;It’s not allowed to annotate &lt;code&gt;abstract&lt;/code&gt; or &lt;code&gt;sealed&lt;/code&gt; classes with &lt;code&gt;@Parcelize&lt;/code&gt;: all concrete child classes that inherit from them must be annotated instead.&lt;/p&gt;

&lt;p&gt;This has a few implications to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s not possible to reuse serialization code from a parent class in a child class, meaning that the generated code needed to serialize a field declared in the parent class will effectively be repeated in every child class;&lt;/li&gt;
&lt;li&gt;All properties that need to be serialized in the &lt;code&gt;abstract&lt;/code&gt; or &lt;code&gt;sealed&lt;/code&gt; class must be declared as &lt;code&gt;abstract&lt;/code&gt; in order to avoid duplicating them in the child class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at an example of a &lt;code&gt;Parcelable&lt;/code&gt; &lt;code&gt;abstract&lt;/code&gt; class.&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&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;wheels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bicycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The common &lt;code&gt;wheels&lt;/code&gt; property should not be serialized and its value is initialized directly by the child classes constructor.&lt;/li&gt;
&lt;li&gt;The common &lt;code&gt;model&lt;/code&gt; and &lt;code&gt;speed&lt;/code&gt; properties need to be serialized in each instance, so they are declared as abstract in the parent &lt;code&gt;Vehicle&lt;/code&gt; class. Then, they are overridden in the primary constructor of all child classes and will be handled by Parcelize.&lt;/li&gt;
&lt;li&gt;Extra properties to serialize could also be added in the primary constructor of the child classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Objects with a parent class
&lt;/h3&gt;

&lt;p&gt;Another interesting feature of Parcelize that has not yet been mentioned is that it supports annotating &lt;a href="https://kotlinlang.org/docs/object-declarations.html" rel="noopener noreferrer"&gt;&lt;code&gt;object&lt;/code&gt;&lt;/a&gt;. At first it would seem useless to support the serialization of a singleton, but it actually makes sense when the &lt;code&gt;object&lt;/code&gt; has a parent class and represents one of the possible values of its parent class.&lt;/p&gt;

&lt;p&gt;This feature is particularly useful when it comes to implement a Parcelable &lt;code&gt;sealed class&lt;/code&gt; where some of the values are &lt;code&gt;object&lt;/code&gt;s. A typical example of such class would look like 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="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;

&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Error&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can take one last look at the bytecode inspector in order to confirm that the generated deserializing code for the &lt;code&gt;object&lt;/code&gt; is indeed returning the existing singleton instance and not a new instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readInt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INSTANCE&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Excluding properties from serialization
&lt;/h2&gt;

&lt;p&gt;Sometimes properties are used to store transient state that must be excluded from serialization. In a typical Java world, the containing class would implement the &lt;code&gt;Serializable&lt;/code&gt; interface and the excluded fields would be annotated with &lt;code&gt;@Transient&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But in our Android world we are using the preferred &lt;code&gt;Parcelable&lt;/code&gt; interface and this annotation is not recognized by Parcelize. Instead, to be exempted from serialization a Kotlin property has to be declared in the body of the class instead of the primary constructor:&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;totalPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@IgnoredOnParcel&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;readPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;readPages&lt;/code&gt; property will be skipped. The IDE will highlight it with a warning message by default, until you annotate it with &lt;code&gt;@IgnoredOnParcel&lt;/code&gt; to make that behavior more explicit.&lt;/p&gt;

&lt;p&gt;Now, is it still possible to pass the initial value of that property through a class constructor like for the other properties? The answer is yes: by using a &lt;strong&gt;secondary constructor&lt;/strong&gt; which delegates to the primary constructor.&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;constructor&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;totalPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@IgnoredOnParcel&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;readPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;readPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;readPages&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readPages&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;In the above example, the primary constructor was made &lt;code&gt;private&lt;/code&gt; so that it’s only callable by the secondary constructor and the generated Parcelable &lt;code&gt;CREATOR&lt;/code&gt;, and external classes have to use the secondary constructor with 3 arguments to create an instance.&lt;/p&gt;

&lt;p&gt;Similarly, it’s possible to use the same technique to achieve the opposite: make private properties serializable without having to pass their initial value through the public class constructor.&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="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClickCounter&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;constructor&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;var&lt;/span&gt; &lt;span class="py"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&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="mi"&gt;0&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;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;count&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;currentValue&lt;/span&gt;
        &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this final example, &lt;code&gt;count&lt;/code&gt; is an internal state variable that will be initialized to &lt;code&gt;0&lt;/code&gt; when the class public constructor is called, and restored to its current value upon deserialization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Use a &lt;code&gt;public&lt;/code&gt; secondary constructor in combination with a &lt;code&gt;private&lt;/code&gt; primary constructor to control which properties you want to be initializable through the public constructor and which properties you want to be serialized.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;And that’s a wrap. This covers everything there is to know about the feature so that, except for rare cases, no Android developer should have to write manual &lt;code&gt;Parcelable&lt;/code&gt; serialization code ever again. If you are aware of other caveats or tips and tricks regarding &lt;em&gt;Parcelize&lt;/em&gt;, feel free to detail them in the comments section.&lt;/p&gt;

&lt;p&gt;Thank you for reading this exceptionally long post. If you liked it, please share or subscribe and stay tuned for more in the coming months.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>androiddev</category>
      <category>android</category>
    </item>
    <item>
      <title>Advanced JSON parsing techniques using Moshi and Kotlin</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Mon, 30 Jul 2018 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/advanced-json-parsing-techniques-using-moshi-and-kotlin-256h</link>
      <guid>https://dev.to/cbeyls/advanced-json-parsing-techniques-using-moshi-and-kotlin-256h</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/square/moshi" rel="noopener noreferrer"&gt;Moshi&lt;/a&gt; is a modern JSON library for Android and Java from Square. It can be considered as the successor to GSON, with a simpler and leaner API and an architecture enabling better performance through the use of the &lt;a href="https://github.com/lysine-dev/okio" rel="noopener noreferrer"&gt;Okio&lt;/a&gt; library. It’s also the most Kotlin-friendly library you can use to parse JSON files, as it comes with Kotlin-aware extensions.&lt;/p&gt;

&lt;p&gt;In this article I’m going to demonstrate how to take advantage of features from both the Moshi library and the Kotlin language itself in order to write efficient and robust JSON parsers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The example model and JSON file
&lt;/h2&gt;

&lt;p&gt;Consider the following model representing a person:&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;Person&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;id&lt;/strong&gt; and &lt;strong&gt;name&lt;/strong&gt; are mandatory properties, while the &lt;strong&gt;age&lt;/strong&gt; is optional with a default value of -1.&lt;/p&gt;

&lt;p&gt;Our objective is to load a list of &lt;code&gt;Person&lt;/code&gt; objects in our application from a JSON file or stream with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lisa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Karen"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this simple example, the JSON object key names exactly match the &lt;code&gt;Person&lt;/code&gt; property names and the &lt;code&gt;"age"&lt;/code&gt; key is also optional.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Fully manual parsing
&lt;/h2&gt;

&lt;p&gt;The most basic way of parsing JSON using Moshi is to use the &lt;strong&gt;streaming API&lt;/strong&gt;, which is similar to the streaming API of GSON and &lt;a href="https://developer.android.com/reference/android/util/JsonReader" rel="noopener noreferrer"&gt;the one provided by the Android Framework&lt;/a&gt;. This gives you the most control over the parsing process, which is especially useful when the JSON source is dirty.&lt;/p&gt;

&lt;p&gt;Typical code would look like 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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ManualParser&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginArray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

            &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextName&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="s"&gt;"id"&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextLong&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="s"&gt;"age"&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipValue&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endObject&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;id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing required field"&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;person&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endArray&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;result&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;h3&gt;
  
  
  Introducing &lt;code&gt;selectName()&lt;/code&gt; for performance
&lt;/h3&gt;

&lt;p&gt;We can further optimize the parser by leveraging a feature introduced in Moshi 1.5: the ability to compare the next bytes of the stream to expected JSON object key names or values. This is done using the &lt;a href="https://square.github.io/moshi/1.x/moshi/com/squareup/moshi/JsonReader.html#selectName-com.squareup.moshi.JsonReader.Options-" rel="noopener noreferrer"&gt;&lt;code&gt;JsonReader.selectName()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://square.github.io/moshi/1.x/moshi/com/squareup/moshi/JsonReader.html#selectString-com.squareup.moshi.JsonReader.Options-" rel="noopener noreferrer"&gt;&lt;code&gt;JsonReader.selectString()&lt;/code&gt;&lt;/a&gt; methods, respectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does that improve performance?&lt;/strong&gt; By looking at the JSON file, you can see that some string values are being repeated multiple times: the key names for the JSON objects are known in advance and match the property names of the &lt;code&gt;Person&lt;/code&gt; class (&lt;code&gt;"id"&lt;/code&gt;, &lt;code&gt;"name"&lt;/code&gt;, &lt;code&gt;"age"&lt;/code&gt;). So instead of letting Moshi decode the UTF-8 string and allocate memory for it every time a key name is encountered in the stream, we can skip that step and simply compare the next bytes of the stream with a preloaded collection of known key names, already encoded in UTF-8. If the byte sequence is found in the collection, its index will be returned by &lt;code&gt;selectName()&lt;/code&gt;. This is made possible using some neat features of the lower-level &lt;a href="https://github.com/lysine-dev/okio" rel="noopener noreferrer"&gt;Okio&lt;/a&gt; library.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Moshi is optimized for, and only works with, JSON files encoded in UTF-8. If you still use a different character encoding in 2018, shame on you.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After replacing &lt;code&gt;nextName()&lt;/code&gt; with &lt;code&gt;selectName()&lt;/code&gt; in the parser, the code now looks like 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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ManualParser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&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;NAMES&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"age"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginArray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

            &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NAMES&lt;/span&gt;&lt;span class="p"&gt;))&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextLong&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="k"&gt;else&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipValue&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endObject&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;id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing required field"&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;person&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endArray&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;result&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;It’s a bit less readable than before since the &lt;code&gt;when&lt;/code&gt; expression now mentions array indices instead of the string values directly. That can be improved by declaring extra constants for these indices in the companion object, at the expense of adding more lines of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reducing boilerplate code using extension functions
&lt;/h3&gt;

&lt;p&gt;The code for reading a JSON array and a JSON object using a streaming API always follows the same patterns. &lt;strong&gt;These patterns can be extracted to extension functions to avoid the repetition.&lt;/strong&gt; This especially improves readability and reduces the risk of errors for JSON files with multiple levels of nested arrays and objects.&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="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipNameAndValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;skipName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;skipValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;beginObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;endObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;beginArray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;endArray&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;It’s recommended to declare the higher-order functions as &lt;code&gt;inline&lt;/code&gt; so that calling them introduces no additional cost compared to the original code (no extra objects allocations) and the bytecode will be identical.&lt;/p&gt;

&lt;p&gt;We can also create another version of &lt;code&gt;readArray()&lt;/code&gt; which goes one step further and builds and returns the list as well.&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;inline&lt;/span&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;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readArrayToList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;List&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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mutableListOf&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;beginArray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&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="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;endArray&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;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using that function, the body of the lambda must return the item to be added to the list, or &lt;code&gt;null&lt;/code&gt; to skip it.&lt;/p&gt;

&lt;p&gt;With these new functions the parser code becomes &lt;strong&gt;much shorter&lt;/strong&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;class&lt;/span&gt; &lt;span class="nc"&gt;ManualParser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&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;NAMES&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"age"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readArrayToList&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

            &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NAMES&lt;/span&gt;&lt;span class="p"&gt;))&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextLong&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipNameAndValue&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing required field"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&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;h3&gt;
  
  
  Immutability, default values and mandatory fields
&lt;/h3&gt;

&lt;p&gt;To be able to enforce the &lt;em&gt;immutability&lt;/em&gt; of the &lt;code&gt;Person&lt;/code&gt; object (all its fields are &lt;code&gt;val&lt;/code&gt;s), we need to pass all the field values at once in its constructor, which means that we need to declare &lt;strong&gt;one extra variable for each field&lt;/strong&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;var&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Variables for optional fields&lt;/strong&gt; (&lt;code&gt;age&lt;/code&gt;) need to be assigned a default value matching the default value of the field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variables for mandatory fields&lt;/strong&gt; (&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;) are assigned an arbitrary default value outside of the range of valid values. &lt;code&gt;null&lt;/code&gt; can also be used as default value for non-null mandatory fields. Then before instantiating the model object, we need to check that these variables have been reassigned valid values, otherwise throw an Exception or skip the item:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing required field"&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;&lt;em&gt;Manual fields validation makes the parser code both more verbose and error-prone because &lt;strong&gt;we need to remember updating the parser every time we change the mandatory fields or update the default values in the model&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We can avoid declaring these variables entirely in the parser by making the model fully &lt;em&gt;mutable&lt;/em&gt; (declaring all fields as &lt;code&gt;var&lt;/code&gt;s) with an empty constructor.&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;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0L&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less lines of code in the parser;&lt;/li&gt;
&lt;li&gt;We can rely on the model default values instead of duplicating them in the parser code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Downsides:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We lose all the benefits of immutability: coherent states, no side effects, thread safety;&lt;/li&gt;
&lt;li&gt;All fields are now declared as optional. We need to document which ones are effectively mandatory and the parser still needs to manually check if they have been assigned a valid value.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Because the downsides outweigh the benefits, I recommend to &lt;strong&gt;always favor immutability in your model objects when you can&lt;/strong&gt;, especially since Kotlin makes this easier than Java.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Moshi’s Kotlin Code Gen
&lt;/h2&gt;

&lt;p&gt;A better way to validate mandatory Kotlin fields and respect default values while keeping the objects immutable is to let Moshi do this work for us by using the automatic JSON to Kotlin converters it provides.&lt;/p&gt;

&lt;p&gt;Moshi has two ways to generate these converters which are called &lt;code&gt;JsonAdapter&lt;/code&gt;s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using reflection, via the &lt;code&gt;moshi-kotlin&lt;/code&gt; artifact. Adapters will be generated at &lt;em&gt;runtime&lt;/em&gt; when needed, then reused. The main downside of this solution is that in order to understand metadata like nullability and default values of Kotlin properties, this artifact depends on the &lt;code&gt;kotlin-reflect&lt;/code&gt; library, a 2.5 MiB jar file which will make your application code size grow significantly.&lt;/li&gt;
&lt;li&gt;Since Moshi 1.6, adapters can also be generated at &lt;em&gt;compile time&lt;/em&gt; using the &lt;code&gt;moshi-kotlin-codegen&lt;/code&gt; annotation processor. This is a much better solution because it provides better performance while adding no extra dependency to your application. The only limitation of that solution compared to &lt;code&gt;kotlin-reflect&lt;/code&gt; is that it is unable to initialize &lt;code&gt;private&lt;/code&gt; or &lt;code&gt;protected&lt;/code&gt; fields without using the class constructor, but the same limitations apply when writing your parsers manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setup moshi-kotlin-codegen
&lt;/h3&gt;

&lt;p&gt;Make sure you enable the &lt;code&gt;kapt&lt;/code&gt; plugin in your application’s &lt;strong&gt;build.gradle&lt;/strong&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'kotlin-kapt'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the annotation processor to your dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;kapt&lt;/span&gt; &lt;span class="s1"&gt;'com.squareup.moshi:moshi-kotlin-codegen:1.6.0'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update (2026):&lt;/strong&gt; Today you should use the KSP annotation processor plugin in place of KAPT which is deprecated and unmaintained. Recent versions of &lt;code&gt;moshi-kotlin-codegen&lt;/code&gt; are compatible with KSP.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now for every Kotlin class for which you want to generate a &lt;code&gt;JsonAdapter&lt;/code&gt; implementation at compile time, add the &lt;code&gt;@JsonClass&lt;/code&gt; annotation on top of it with the &lt;code&gt;generateAdapter&lt;/code&gt; element set to &lt;code&gt;true&lt;/code&gt;. In this example, we’ll add it to the &lt;code&gt;Person&lt;/code&gt; class.&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="nd"&gt;@JsonClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generateAdapter&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the generated parser will match the property names with the JSON object key names. To override that, add the &lt;a href="https://square.github.io/moshi/1.x/moshi/com/squareup/moshi/Json.html" rel="noopener noreferrer"&gt;&lt;code&gt;@Json&lt;/code&gt;&lt;/a&gt; annotation on the property to specify its JSON key name.&lt;/p&gt;

&lt;p&gt;Moshi also allows to fully customize the way each property is converted from or to JSON, by using custom annotations associated with your own custom type adapters. For more information, check out &lt;a href="https://github.com/square/moshi#alternate-type-adapters-with-jsonqualifier" rel="noopener noreferrer"&gt;the official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A look at the generated code
&lt;/h3&gt;

&lt;p&gt;When building the project, the annotation processor will create a new Kotlin class called &lt;code&gt;PersonJsonAdapter&lt;/code&gt;. Let’s evaluate its code quality.&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;PersonJsonAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;moshi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Moshi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"age"&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;longAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Long&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;moshi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;nonNull&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;stringAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&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;moshi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;nonNull&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;intAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&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;moshi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;nonNull&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;toString&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"GeneratedJsonAdapter(Person)"&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;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;))&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;longAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Non-null value 'id' was null at ${reader.path}"&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stringAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Non-null value 'name' was null at ${reader.path}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Non-null value 'age' was null at ${reader.path}"&lt;/span&gt;&lt;span class="p"&gt;)&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;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Unknown name, skip it.&lt;/span&gt;
                    &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipValue&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
                        &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Required property 'id' missing at ${reader.path}"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
                        &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;JsonDataException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Required property 'name' missing at ${reader.path}"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age&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;result&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;toJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonWriter&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="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Removed for brevity&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;We can notice that this code is quite similar to what we wrote in the manual parser.&lt;/p&gt;

&lt;p&gt;It uses &lt;code&gt;selectName()&lt;/code&gt; for better performance, which is good. The &lt;code&gt;options&lt;/code&gt; are not stored inside a companion object but it doesn’t matter because a &lt;code&gt;JsonAdapter&lt;/code&gt; is only instantiated once then reused, making it effectively a singleton. Non-null properties are enforced. Mandatory fields are properly checked and an exception is thrown when they are missing.&lt;/p&gt;

&lt;p&gt;Only two things aren’t perfect compared to a smart manually-written parser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nullable variables are used to store values of non-null primitive types (&lt;code&gt;Long&lt;/code&gt;, &lt;code&gt;Int&lt;/code&gt;) and generic adapters are used to read them ( &lt;code&gt;longAdapter&lt;/code&gt;, &lt;code&gt;intAdapter&lt;/code&gt;), which means unnecessary &lt;strong&gt;boxing&lt;/strong&gt; will occur when reading these values.&lt;/li&gt;
&lt;li&gt;For each item, &lt;strong&gt;two instances&lt;/strong&gt; of &lt;code&gt;Person&lt;/code&gt; are created instead of one. The reason behind this is to allow reading back all the default values of optional fields from the first instance when creating the second, final instance.
This should not cause any performance issue, &lt;strong&gt;unless your model class includes heavy initialization code&lt;/strong&gt; that you want to avoid doing twice.
This also means that when all fields are mandatory, only one instance will be created by the adapter.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;These are minor performance issues, so I recommend that you use the automatically generated Kotlin &lt;code&gt;JsonAdapter&lt;/code&gt;s when both your code and the JSON data source allow it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update (2026):&lt;/strong&gt; The code generator in Moshi 1.9.0 (released in 2019) is now able to call the Kotlin synthetic constructor that handles default values for optional fields. A single instance of each object is now created in every case and this limitation doesn't exist anymore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using the generated adapters
&lt;/h3&gt;

&lt;p&gt;It’s preferred to use the Moshi API to retrieve adapter instances, because it will automatically locate the class, create a single instance of it and put it in a cache so it can be shared between parsers.&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;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;moshi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated adapter converts JSON to a single &lt;code&gt;Person&lt;/code&gt; object. But the JSON file contains an &lt;strong&gt;array&lt;/strong&gt; of persons so we want to retrieve a &lt;code&gt;List&amp;lt;Person&amp;gt;&lt;/code&gt; instead. There are two ways to achieve this.&lt;/p&gt;

&lt;p&gt;First, we can ask Moshi to build a generic list adapter which will use the generated &lt;code&gt;PersonJsonAdapter&lt;/code&gt; under the hood. This is done by using Moshi’s &lt;code&gt;Types&lt;/code&gt; utility class to build a type representing &lt;code&gt;List&amp;lt;Person&amp;gt;&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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;listType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newParameterizedType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&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;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;moshi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listType&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&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;&lt;strong&gt;Update (2026):&lt;/strong&gt; Moshi 1.11.0 (released in 2020) provides a new experimental &lt;a href="https://square.github.io/moshi/1.x/moshi/moshi/com.squareup.moshi/adapter.html" rel="noopener noreferrer"&gt;&lt;code&gt;adapter()&lt;/code&gt;&lt;/a&gt; extension function using Kotlin's reified &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.reflect/type-of.html" rel="noopener noreferrer"&gt;&lt;code&gt;typeOf()&lt;/code&gt;&lt;/a&gt; function to resolve the type at compile time. So in Kotlin you don't need to use the &lt;code&gt;Types&lt;/code&gt; class anymore and you can simply write this:&lt;/p&gt;


&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;moshi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adapter&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;But more interestingly, we can also use the generated adapters &lt;strong&gt;inside our own parsers&lt;/strong&gt;, effectively &lt;strong&gt;mixing and matching manual and automatic parsing&lt;/strong&gt;. This is especially useful when the JSON source is not very well structured or contains a lot of unnecessary layers that we want to skip, but at the same time we still want to leverage the automatic parsing in some parts of the file.&lt;/p&gt;

&lt;p&gt;For our example, we can write a hybrid parser which builds a list of &lt;code&gt;Person&lt;/code&gt; objects while filtering out children and people of unknown age:&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;HybridParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;moshi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Moshi&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;personAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;moshi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readArrayToList&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;personAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;takeIf&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="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&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;We start by manually parsing the JSON array using the &lt;code&gt;readArrayToList()&lt;/code&gt; extension function defined earlier. It was designed to not add the item to the list when the lambda returns &lt;code&gt;null&lt;/code&gt;, so we can use &lt;code&gt;takeIf()&lt;/code&gt; to filter out items.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Generated &lt;code&gt;JsonAdapter&lt;/code&gt;s are a great way to remove boilerplate code from manual JSON parsers.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Of course, you can also write your own custom &lt;code&gt;JsonAdapter&lt;/code&gt;s and reuse them in your code.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to learn more about Moshi’s Kotlin Code Gen, you can read &lt;a href="https://www.zacsweers.dev/exploring-moshis-kotlin-code-gen/" rel="noopener noreferrer"&gt;this excellent article&lt;/a&gt; from its main contributor, Zac Sweers.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Coroutines magic for big data sources
&lt;/h2&gt;

&lt;p&gt;In the previous example we saw how to filter out items inside the parser. Now, what if we wanted to filter out items from outside the parser, or wanted to process parsed items one by one, &lt;strong&gt;without storing them all at once into memory?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can achieve this by creating a lazy streaming parser which returns a Kotlin &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.sequences/" rel="noopener noreferrer"&gt;&lt;code&gt;Sequence&lt;/code&gt;&lt;/a&gt; instead of a &lt;code&gt;List&lt;/code&gt;. Sequences allow to keep memory usage under control when dealing with potentially huge JSON lists, as they only deal with one item at a time and all processing is delayed until their final collection. A &lt;code&gt;Sequence&lt;/code&gt; can also be converted to an &lt;code&gt;Iterable&lt;/code&gt; for Java compatibility.&lt;/p&gt;

&lt;p&gt;While it is possible to manually write a custom &lt;code&gt;Sequence&lt;/code&gt; with a custom &lt;code&gt;Iterator&lt;/code&gt; which will resume parsing every time &lt;code&gt;next()&lt;/code&gt; is called, it is not an easy task. It requires some mental gymnastics because the parsing code, instead of being structured hierarchically like the JSON file in one single block, has to be split into separate parts sharing the same state.&lt;/p&gt;

&lt;p&gt;Fortunately, there is an easier way thanks to &lt;strong&gt;Kotlin’s coroutines&lt;/strong&gt; which allow to build a lazy sequence using only a single block of synchronous code and the &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.sequences/-sequence-scope/yield.html" rel="noopener noreferrer"&gt;&lt;code&gt;yield()&lt;/code&gt;&lt;/a&gt; suspending function.&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;LazyParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;moshi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Moshi&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;personAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;moshi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonReader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;sequence&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readArray&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;personAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is very simple. It’s similar to building a list in one go, except that the calls to add an item to the list are replaced with &lt;code&gt;yield(item)&lt;/code&gt;. The parser will effectively stop at that point, preserving its state, then resume later when the next item of the &lt;code&gt;Sequence&lt;/code&gt; is requested by the caller. That’s all the code needed to create a fully lazy JSON parser in Kotlin.&lt;/p&gt;

&lt;p&gt;It’s then possible filter out items, iterate over them or do anything else lazily outside of the parser:&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;sequence&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LazyParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;moshi&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&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;filteredList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sequence&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="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;toList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;I hope this article was able to inspire you to make your JSON parsers cleaner, faster and fun. Feel free to share it and also ask questions or provide more examples in the comments. Happy coding!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>androiddev</category>
      <category>json</category>
      <category>moshi</category>
    </item>
    <item>
      <title>Architecture Components pitfalls: LiveData and the Fragment lifecycle</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Mon, 23 Oct 2017 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/architecture-components-pitfalls-livedata-and-the-fragment-lifecycle-1da0</link>
      <guid>https://dev.to/cbeyls/architecture-components-pitfalls-livedata-and-the-fragment-lifecycle-1da0</guid>
      <description>&lt;p&gt;The new &lt;a href="https://developer.android.com/topic/libraries/architecture/" rel="noopener noreferrer"&gt;Android Architecture Components&lt;/a&gt; are soon to be announced as stable after a few months of public testing.&lt;/p&gt;

&lt;p&gt;A lot has already been written about the basics (starting with the very good documentation) so I won’t cover them here. Instead I would like to focus on important pitfalls that are mostly undocumented and rarely discussed and may cause issues in your applications if you miss them. In this article, I’ll talk about our beloved &lt;em&gt;Fragments&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Edit (14 may 2018)&lt;/strong&gt;: Google has finally fixed the issue in support library 28.0.0 and AndroidX 1.0.0. See &lt;strong&gt;solution 4&lt;/strong&gt; below.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Edit (13 march 2020)&lt;/strong&gt;: &lt;code&gt;onActivityCreated()&lt;/code&gt; has been officially deprecated and &lt;code&gt;onViewCreated()&lt;/code&gt; should be used instead. The code samples in this article have been updated accordingly.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The Architecture Components provide default &lt;code&gt;ViewModelProvider&lt;/code&gt; implementations for activities and fragments. They allow you to store &lt;a href="https://developer.android.com/topic/libraries/architecture/livedata.html" rel="noopener noreferrer"&gt;&lt;code&gt;LiveData&lt;/code&gt;&lt;/a&gt; instances inside a &lt;a href="https://developer.android.com/topic/libraries/architecture/viewmodel" rel="noopener noreferrer"&gt;&lt;code&gt;ViewModel&lt;/code&gt;&lt;/a&gt; to be reused across configuration changes. The usage with activities is quite straightforward because the activity lifecyle maps well to the &lt;a href="https://developer.android.com/reference/androidx/lifecycle/Lifecycle" rel="noopener noreferrer"&gt;&lt;code&gt;Lifecycle&lt;/code&gt;&lt;/a&gt; interface of the Architecture Components, but &lt;strong&gt;the &lt;a href="https://developer.android.com/guide/fragments/lifecycle" rel="noopener noreferrer"&gt;fragment lifecycle&lt;/a&gt; is more complex&lt;/strong&gt; and may cause subtle side effects if you’re not being careful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa0ldgkbuvexqqdjwtonl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa0ldgkbuvexqqdjwtonl.jpg" alt="The Fragment lifecycle (simplified version)" width="800" height="900"&gt;&lt;/a&gt;&lt;/p&gt;
The Fragment lifecycle (simplified version)



&lt;p&gt;&lt;strong&gt;Fragments can be detached and re-attached.&lt;/strong&gt; When they are detached, their view hierarchy is destroyed and they become invisible and inactive, but their instance is not destroyed. When they are later re-attached, a new view hierarchy is created and &lt;code&gt;onCreateView()&lt;/code&gt; and &lt;code&gt;onViewCreated()&lt;/code&gt; are called again.&lt;/p&gt;

&lt;p&gt;For this reason, the usually recommended place to initialize &lt;code&gt;Loader&lt;/code&gt;s and other asynchronous loading operations that will eventually interact with the view hierarchy is in &lt;code&gt;onViewCreated()&lt;/code&gt;. We can assume this is also the best place to initialize &lt;code&gt;LiveData&lt;/code&gt; instances by subscribing a new &lt;code&gt;Observer&lt;/code&gt;. Most of the &lt;a href="https://github.com/android/architecture-components-samples" rel="noopener noreferrer"&gt;official Architecture Components samples&lt;/a&gt; also do it there. You would expect typical code to look like 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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Page1Fragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&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;var&lt;/span&gt; &lt;span class="py"&gt;textView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TextView&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&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;onCreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LayoutInflater&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewGroup&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;View&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;view&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fragment_page1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;container&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;textView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&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;view&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;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&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;vm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewModelProviders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&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="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Page1ViewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&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="nc"&gt;Observer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;text&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="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onDestroyView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDestroyView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;textView&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;There is a hidden problem with this code.&lt;/strong&gt; We subscribe an anonymous observer within the lifespan of the fragment (using the fragment as &lt;code&gt;LifecycleOwner&lt;/code&gt;), which means it will automatically be unsubscribed when the fragment is destroyed. However, &lt;strong&gt;when the fragment is detached and re-attached, it is not destroyed&lt;/strong&gt; and a new identical observer instance will be added in &lt;code&gt;onViewCreated()&lt;/code&gt;, while the previous one has not been removed! The result is a growing number of identical observers being active at the same time and the same code being executed multiple times, which is both a memory leak and a performance problem (until the fragment is destroyed).&lt;/p&gt;

&lt;p&gt;This problem concerns any fragment subscribing an observer for its own lifecycle in &lt;code&gt;onCreateView()&lt;/code&gt; or later, without taking any other extra step to unsubscribe it.&lt;/p&gt;

&lt;p&gt;Worse: it also impacts &lt;strong&gt;&lt;a href="https://developer.android.com/reference/androidx/fragment/app/Fragment#setRetainInstance(boolean)" rel="noopener noreferrer"&gt;retained fragments&lt;/a&gt;&lt;/strong&gt;, which are not destroyed during configuration changes but re-attached to a new Activity.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How do we solve this?&lt;/em&gt; There are a few solutions to explore, some better than others. Here are the ones I found so far.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Observing in &lt;code&gt;onCreate()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Your first attempt may be to simply move the observer subscription to &lt;code&gt;onCreate()&lt;/code&gt; instead of &lt;code&gt;onViewCreated()&lt;/code&gt;. But it won’t work as expected without adding more boilerplate code: &lt;code&gt;LiveData&lt;/code&gt; keeps track of which result has been delivered to which observer, and &lt;strong&gt;it won’t deliver the latest result again to a new view hierarchy because the observer hasn’t changed&lt;/strong&gt;. This means you have to manually check for a latest result and bind it to the new view hierarchy in &lt;code&gt;onViewCreated()&lt;/code&gt; which is not very elegant:&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewModelProviders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&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="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Page1ViewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&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="nc"&gt;Observer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bindResult&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;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bindResult&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="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;bindResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Note that the binding code needs to be called at two different places, so you can’t just write an inline anonymous observer. And finally, there is no way with the current &lt;code&gt;LiveData&lt;/code&gt; API to differentiate a &lt;code&gt;null&lt;/code&gt; result from no result for the current value, so it’s better not to return any &lt;code&gt;null&lt;/code&gt; result (for instance in case of error) when using this solution, which overall is probably the worst one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Edit (2023)&lt;/strong&gt;: version 2.3.0 of the Lifecycle library finally added a new method &lt;a href="https://developer.android.com/reference/androidx/lifecycle/LiveData#isInitialized()" rel="noopener noreferrer"&gt;&lt;code&gt;LiveData.isInitialized()&lt;/code&gt;&lt;/a&gt; to allow determining if a &lt;code&gt;LiveData&lt;/code&gt; instance contains a (possibly &lt;code&gt;null&lt;/code&gt;) result.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  2. Manually unsubscribing the observer in &lt;code&gt;onDestroyView()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is a bit better than the first solution but you still can’t use an inline anonymous observer. You must declare it as a final field, subscribe it in &lt;code&gt;onViewCreated()&lt;/code&gt; and also not forget to unsubscribe it in &lt;code&gt;onDestroyView()&lt;/code&gt;, so there is still boilerplate code and room for errors.&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;observer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Observer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&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;textView&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;text&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewModelProviders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&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="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Page1ViewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&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;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&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="n"&gt;observer&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;onDestroyView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDestroyView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;textView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myData&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="n"&gt;observer&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;One of the main benefits of using &lt;code&gt;LiveData&lt;/code&gt; being that it takes care of unsubscribing the observer for you, it’s a pity that it has to be done manually in this case. Keep reading, we can still do better.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Resetting an existing observer
&lt;/h2&gt;

&lt;p&gt;It’s not actually required to unsubscribe the current observer precisely in &lt;code&gt;onDestroyView()&lt;/code&gt;, because it will eventually be unsubscribed automatically in &lt;code&gt;onDestroy()&lt;/code&gt;. What’s important is that it’s unsubscribed &lt;strong&gt;before an identical one is subscribed in &lt;code&gt;onViewCreated()&lt;/code&gt;&lt;/strong&gt;, in order to avoid duplicates. Therefore, another valid solution is to unsubscribe right before subscribing, using for example this Kotlin extension function:&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;LiveData&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;reObserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&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;observer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Observer&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="nf"&gt;removeObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;observer&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;Removing and adding back the same observer will effectively reset its state so that &lt;code&gt;LiveData&lt;/code&gt; will deliver the latest result again automatically during &lt;code&gt;onStart()&lt;/code&gt;, if any. The above function can be used like 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="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;observer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Observer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&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;textView&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;text&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&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;vm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewModelProviders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&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="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Page1ViewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reObserve&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="n"&gt;observer&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 fragment code is now less error-prone because there is one less callback to add, but we still need to declare the observer instance as a final field and reuse it, or else unsubscription will silently fail. Despite this, it’s probably my personal favorite solution for a quick workaround.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Creating a custom Lifecyle for view hierarchies
&lt;/h2&gt;

&lt;p&gt;Ideally, we would want observers subscribed in &lt;code&gt;onViewCreated()&lt;/code&gt; to be automatically unsubscribed in &lt;code&gt;onDestroyView()&lt;/code&gt;. This means we actually want to follow the &lt;em&gt;current view hierarchy lifecycle&lt;/em&gt;, which is different from the &lt;em&gt;fragment lifecycle&lt;/em&gt;. One way to achieve this is to create a custom &lt;code&gt;Fragment&lt;/code&gt; which provides an additional custom &lt;a href="https://developer.android.com/reference/androidx/lifecycle/LifecycleOwner" rel="noopener noreferrer"&gt;&lt;code&gt;LifecycleOwner&lt;/code&gt;&lt;/a&gt; for the current view hierarchy. Here is an implementation in Java.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Thanks to the custom &lt;code&gt;LifecycleOwner&lt;/code&gt; returned by &lt;code&gt;getViewLifecycleOwner()&lt;/code&gt;, the &lt;code&gt;LiveData&lt;/code&gt; observers will be automatically unsubscribed when the view hierarchy is destroyed and nothing else has to be done.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: &lt;code&gt;onViewCreated()&lt;/code&gt; won’t be called if &lt;code&gt;onCreateView()&lt;/code&gt; returns &lt;code&gt;null&lt;/code&gt;, so the custom &lt;code&gt;LifecycleOwner&lt;/code&gt; won’t be created for headless fragments and &lt;code&gt;getViewLifecycleOwner()&lt;/code&gt; will also return &lt;code&gt;null&lt;/code&gt; in that case.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this solution the code is now nearly identical to the initial code sample, but this time it does the right thing.&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&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;vm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewModelProviders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&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="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Page1ViewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&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="nc"&gt;Observer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;text&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The downside is that it requires inheriting from a custom &lt;code&gt;Fragment&lt;/code&gt; implementation. It is also possible to implement the same functionality without inheritance but then it requires declaring a delegate helper class inside each fragment where that custom &lt;code&gt;LifecycleOwner&lt;/code&gt; is needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Edit (14 may 2018)&lt;/strong&gt;: Google implemented this solution directly in support library 28.0.0 and AndroidX 1.0.0. All fragments now provide an additional &lt;code&gt;getViewLifecycleOwner()&lt;/code&gt; method just like in the above sample, so you don’t need to implement it yourself.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Using Data Binding
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fje863s8jz6ducfw3e2f3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fje863s8jz6ducfw3e2f3.jpg" alt="The " width="500" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This section has been rewritten following the release of Android Studio 3.1 and the described solution is considered production-ready.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This last solution provides the cleanest architecture, at the expense of depending on an additional library. It consists of using the &lt;a href="https://developer.android.com/topic/libraries/data-binding/index.html" rel="noopener noreferrer"&gt;Android Data Binding Library&lt;/a&gt; to automatically bind your model to the current view hierarchy, and to simplify things the model will be the &lt;code&gt;ViewModel&lt;/code&gt; instance already used to contain the various &lt;code&gt;LiveData&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With that architecture, the &lt;code&gt;LiveData&lt;/code&gt; instances exposed by the &lt;code&gt;ViewModel&lt;/code&gt; will be automatically observed by the generated &lt;code&gt;Binding&lt;/code&gt; class instead of the fragment itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;layout&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;data&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;variable&lt;/span&gt;
            &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewModel"&lt;/span&gt;
            &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"my.app.viewmodel.Page1ViewModel"&lt;/span&gt;
            &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/data&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/result"&lt;/span&gt;
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"@style/TextAppearance.AppCompat.Large"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
        &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"@{viewModel.myData}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/layout&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The layout declares a variable of type &lt;code&gt;Page1ViewModel&lt;/code&gt; and binds the &lt;code&gt;TextView&lt;/code&gt;’s &lt;code&gt;android:text&lt;/code&gt; property directly to the &lt;code&gt;LiveData&lt;/code&gt; field. When the &lt;code&gt;LiveData&lt;/code&gt; is updated, the &lt;code&gt;TextView&lt;/code&gt; will immediately reflect its new value.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: The ability to bind &lt;code&gt;LiveData&lt;/code&gt; fields directly to views and make the &lt;code&gt;Binding&lt;/code&gt; classes lifecycle-aware has been added in &lt;strong&gt;Android Studio 3.1&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;ViewModel&lt;/code&gt; will always reflect the latest visual state of the fragment, even when no view hierarchy is currently attached to it. &lt;strong&gt;Each time a view hierarchy is created through a &lt;code&gt;Binding&lt;/code&gt; class, it will register itself as a new observer on the &lt;code&gt;LiveData&lt;/code&gt; instances, so we don’t have to manage any observer manually anymore&lt;/strong&gt; and we got rid of the problem.&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;Page1Fragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Page1ViewModel&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;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;vm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ViewModelProviders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;of&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="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Page1ViewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&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;onCreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LayoutInflater&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewGroup&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;View&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;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FragmentPage1Binding&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;container&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;binding&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;vm&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;setLifecycleOwner&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&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;Since the &lt;code&gt;LifecycleOwner&lt;/code&gt; is passed to the &lt;code&gt;Binding&lt;/code&gt; instance, the &lt;code&gt;LiveData&lt;/code&gt; loading logic will still comply with the lifecycle of the current fragment: the views will only be updated while the fragment is started and the internal observers will be properly unsubscribed in &lt;code&gt;onDestroy()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, the special &lt;code&gt;LiveData&lt;/code&gt; observers used by the &lt;code&gt;Binding&lt;/code&gt; classes use &lt;strong&gt;weak references&lt;/strong&gt; internally so they will eventually be unregistered automatically after their associated view hierarchy has been destroyed and garbage collected, even if the fragment itself has not been destroyed yet.&lt;/p&gt;

&lt;p&gt;Overall, this simplifies the fragment by removing the tricky observers logic along with all the &lt;code&gt;View&lt;/code&gt; boilerplate code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final warning
&lt;/h2&gt;

&lt;p&gt;This issue should be taken seriously because detaching a fragment is a very common operation. For instance, it happens when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Switching between sections in the main activity of an app;&lt;/li&gt;
&lt;li&gt;Navigating between pages in a &lt;code&gt;ViewPager&lt;/code&gt; using a &lt;code&gt;FragmentPagerAdapter&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;A fragment is replaced with another one and the transaction is added to the back stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, when a fragment is detached, all its child fragments are detached as well. When in doubt, it’s better to assume that any fragment will eventually be detached at some point and properly handle this case from day 1.&lt;/p&gt;




&lt;p&gt;Now you are aware of this behavior and have at least a few options to work around it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Edit (14 may 2018)&lt;/strong&gt;: Google decided to implement solution 4 directly in support library 28.0.0 and AndroidX 1.0.0. I now recommend that you register your observers using the special lifecycle returned by &lt;code&gt;getViewLifecycleOwner()&lt;/code&gt; in &lt;code&gt;onCreateView()&lt;/code&gt;.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;I like to think that this article played a part in Google fixing this issue and picking up the proposed solution.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don’t hesitate to discuss this in the comments section and please share if you like.&lt;/p&gt;

</description>
      <category>android</category>
      <category>androiddev</category>
      <category>kotlin</category>
      <category>fragments</category>
    </item>
    <item>
      <title>Kotlin singletons with argument</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Fri, 25 Aug 2017 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/kotlin-singletons-with-argument-53o7</link>
      <guid>https://dev.to/cbeyls/kotlin-singletons-with-argument-53o7</guid>
      <description>&lt;p&gt;In Kotlin, the singleton pattern is used as a replacement for static members and fields that don’t exist in that programming language. A singleton is created by simply &lt;a href="https://kotlinlang.org/docs/object-declarations.html" rel="noopener noreferrer"&gt;declaring an &lt;code&gt;object&lt;/code&gt;&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;object&lt;/span&gt; &lt;span class="nc"&gt;SomeSingleton&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contrary to a &lt;code&gt;class&lt;/code&gt;, an &lt;code&gt;object&lt;/code&gt; can’t have any constructor, but &lt;code&gt;init&lt;/code&gt; blocks are allowed if some initialization code is needed.&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;object&lt;/span&gt; &lt;span class="nc"&gt;SomeSingleton&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"init complete"&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;The object will be instantiated and its init blocks will be executed lazily &lt;em&gt;upon first access&lt;/em&gt;, in a thread-safe way. To achieve this, a Kotlin object actually relies on a Java &lt;strong&gt;static initialization block&lt;/strong&gt;. The above Kotlin object will be compiled to the following equivalent Java code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeSingleton&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SomeSingleton&lt;/span&gt; &lt;span class="no"&gt;INSTANCE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;SomeSingleton&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="no"&gt;INSTANCE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SomeSingleton&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"init complete"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SomeSingleton&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the preferred way to implement singletons on a JVM because it enables thread-safe lazy initialization without having to rely on a locking algorithm like the complex &lt;a href="https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java" rel="noopener noreferrer"&gt;double-checked locking&lt;/a&gt;. By simply using an &lt;code&gt;object&lt;/code&gt; declaration in Kotlin, you are guaranteed to get a safe and efficient singleton implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy0kn2bbajoj7hxz127ov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy0kn2bbajoj7hxz127ov.png" alt="Singletons: forever alone" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
Singletons: forever alone



&lt;h2&gt;
  
  
  Passing an argument
&lt;/h2&gt;

&lt;p&gt;But what if the initialization code requires some extra argument? Because a Kotlin &lt;code&gt;object&lt;/code&gt; can’t have any constructor, you can’t pass any argument to it.&lt;/p&gt;

&lt;p&gt;There are valid cases for which passing an argument to a singleton initialization block is the recommended pattern. The alternative requires the singleton class to be aware of some external component to be able to retrieve that argument, violating the principle of separation of concerns and making the code less reusable. To mitigate the issue, that external component could be a &lt;em&gt;dependency injection&lt;/em&gt; system. It’s a valid solution but you don’t always want to use that kind of library and there are some cases where it can’t be used, like we’ll see in the following Android example.&lt;/p&gt;

&lt;p&gt;Another scenario where you have to rely on a different way to manage a singleton in Kotlin is when the concrete implementation of the singleton is generated by an external tool or library (Retrofit, Room, …) and its instance is retrieved using a custom builder or factory method. In that case, you usually declare the singleton as an interface or abstract class and it can’t be an &lt;code&gt;object&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Android use case
&lt;/h2&gt;

&lt;p&gt;On the Android platform, you often need to pass a &lt;code&gt;Context&lt;/code&gt; instance to initialization blocks of singleton components so they can retrieve file paths, read settings or access services, but you also want to &lt;strong&gt;avoid keeping a static reference to it&lt;/strong&gt; (even if a static reference to the application Context is technically safe). There are two ways to achieve that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Early initialization&lt;/strong&gt;: All components are initialized by calling their public init functions at startup time in &lt;code&gt;Application.onCreate()&lt;/code&gt; where the application Context is available, before (almost) any other code runs. This simple solution has the main downside of &lt;strong&gt;slowing down the application startup&lt;/strong&gt; by blocking the main thread, initializing all components including those that are not going to be used immediately. Another less known issue is that &lt;a href="https://developer.android.com/guide/topics/providers/content-providers.html" rel="noopener noreferrer"&gt;content providers&lt;/a&gt; may be created before this method is called (as stated in the documentation), so if a content provider makes use of a global application component, that component must be able to be initialized before &lt;code&gt;Application.onCreate()&lt;/code&gt; or your application may crash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy initialization&lt;/strong&gt;: This is the recommended way. The component is a singleton and a function returning its instance takes a &lt;code&gt;Context&lt;/code&gt; argument. The singleton instance will be created and initialized using this argument the first time it’s invoked. &lt;em&gt;This requires some synchronization mechanism in order to be thread-safe.&lt;/em&gt;
An example of standard Android component using this pattern is &lt;code&gt;LocalBroadcastManager&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;LocalBroadcastManager&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="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sendBroadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A reusable Kotlin implementation
&lt;/h2&gt;

&lt;p&gt;We can encapsulate the logic to lazily create and initialize a singleton with argument inside a &lt;code&gt;SingletonHolder&lt;/code&gt; class. In order to make that logic thread-safe, we need to implement a &lt;strong&gt;synchronized algorithm&lt;/strong&gt; and the most efficient one — which is also the hardest to get right — is the double-checked locking algorithm.&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;open&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SingletonHolder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;creator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&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;var&lt;/span&gt; &lt;span class="py"&gt;creator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;creator&lt;/span&gt;
    &lt;span class="nd"&gt;@Volatile&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;T&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;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instance&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;i&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&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;synchronized&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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;i2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instance&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;i2&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="n"&gt;i2&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;created&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;creator&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt;
                &lt;span class="n"&gt;creator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                &lt;span class="n"&gt;created&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;Note that adding the &lt;code&gt;@Volatile&lt;/code&gt; annotation to the instance field is required for the algorithm to work properly.&lt;/p&gt;

&lt;p&gt;This may not be the most compact or elegant Kotlin code, but it’s the one producing the most efficient bytecode for the double-checked locking algorithm. &lt;strong&gt;Trust the Kotlin authors on this&lt;/strong&gt;: this code is actually borrowed directly from the implementation of the &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/lazy.html" rel="noopener noreferrer"&gt;&lt;code&gt;lazy()&lt;/code&gt;&lt;/a&gt; function in the Kotlin standard library, which is synchronized by default. It has been modified to allow passing an argument to the creator function.&lt;/p&gt;

&lt;p&gt;Given its relative complexity, it’s not the kind of code you want to write (or read) more than once, so the goal is to reuse that &lt;code&gt;SingletonHolder&lt;/code&gt; class every time you have to implement a singleton with argument.&lt;/p&gt;

&lt;p&gt;The logical place to declare the &lt;code&gt;getInstance()&lt;/code&gt; function is inside the &lt;em&gt;companion object&lt;/em&gt; of the singleton class, which allows it to be called by using simply the singleton class name as qualifier, similarly to a static method in Java. &lt;strong&gt;One powerful feature that Kotlin companion objects offer is their ability to inherit from a base class&lt;/strong&gt; like any other &lt;code&gt;object&lt;/code&gt;, which enables something comparable to static-only inheritance. In this case, we want to use &lt;code&gt;SingletonHolder&lt;/code&gt; as a base class for the companion object of the singleton, in order to reuse and automatically expose its &lt;code&gt;getInstance()&lt;/code&gt; function on the singleton class.&lt;/p&gt;

&lt;p&gt;As for the creator function passed as argument to the &lt;code&gt;SingletonHolder&lt;/code&gt; constructor, a custom lambda could be declared inline but the common solution is to &lt;strong&gt;pass a reference to the private constructor of the singleton class&lt;/strong&gt;. The final code for a singleton with argument would look like 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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Manager&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;constructor&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="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="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Init using context argument&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SingletonHolder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Manager&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;&amp;gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Manager&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;Not as short as the &lt;code&gt;object&lt;/code&gt; notation, but probably the next best thing.&lt;/p&gt;

&lt;p&gt;The singleton may now be invoked using the following syntax and its initialization will be lazy and thread-safe:&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="nc"&gt;Manager&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="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;doStuff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use this idiom when a singleton implementation is generated by an external library and the builder requires an argument. Here’s an example using the &lt;a href="https://developer.android.com/training/data-storage/room" rel="noopener noreferrer"&gt;Room Persistence Library&lt;/a&gt; for Android:&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="nd"&gt;@Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;arrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;version&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="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersDatabase&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RoomDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;userDao&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;UserDao&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SingletonHolder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UsersDatabase&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;&amp;gt;({&lt;/span&gt;
        &lt;span class="nc"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;databaseBuilder&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="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;UsersDatabase&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Sample.db"&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&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;&lt;strong&gt;Note&lt;/strong&gt;: When the builder &lt;strong&gt;doesn’t require an argument&lt;/strong&gt;, you can simply use a &lt;code&gt;lazy&lt;/code&gt; delegated property instead:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;GitHubService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&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;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GitHubService&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;lazy&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;retrofit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Retrofit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.github.com/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;retrofit&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="nc"&gt;GitHubService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&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;I hope you found these code snippets useful. If you want to suggest other ways to solve this problem or have questions, don’t hesitate to start a discussion in the comments section. Thank you for reading!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>androiddev</category>
      <category>android</category>
    </item>
    <item>
      <title>Reducing Parcelable boilerplate code using Kotlin</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Fri, 14 Jul 2017 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/reducing-parcelable-boilerplate-code-using-kotlin-j4c</link>
      <guid>https://dev.to/cbeyls/reducing-parcelable-boilerplate-code-using-kotlin-j4c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update (november 2019)&lt;/strong&gt;: I published a detailed &lt;a href="https://dev.to/cbeyls/a-study-of-the-parcelize-feature-from-kotlin-android-extensions-53f0"&gt;new article&lt;/a&gt; about how to use Parcelize to have your Parcelable boilerplate code generated automatically by a Kotlin plugin. This is the preferred method to implement &lt;code&gt;Parcelable&lt;/code&gt; in Kotlin today, even if there are still exceptional cases for which you want to write this code manually in Kotlin. The following article will help you for those cases.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Implementing the &lt;a href="https://developer.android.com/reference/android/os/Parcelable.html" rel="noopener noreferrer"&gt;&lt;code&gt;Parcelable&lt;/code&gt;&lt;/a&gt; interface and maintaining this code remains a painful day-to-day task for Android developers. Surely, Android Studio can now automatically generate most of the boilerplate code, but this doesn’t work for all member types and most importantly, the result is quite verbose and clutters classes, decreasing their readability.&lt;/p&gt;

&lt;h2&gt;
  
  
  About Parcelable libraries
&lt;/h2&gt;

&lt;p&gt;Annotation processor libraries like &lt;a href="https://grandstaish.github.io/paperparcel/" rel="noopener noreferrer"&gt;PaperParcel&lt;/a&gt; are able to automatically generate Parcelable implementations and get rid of some of the boilerplate code. This is fine, but I don’t use these solutions because &lt;strong&gt;I like to have full control over the serialization process&lt;/strong&gt;. These libraries come with their limitations. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many of these libraries serialize types like &lt;code&gt;Enum&amp;lt;T&amp;gt;&lt;/code&gt; or &lt;code&gt;BigDecimal&lt;/code&gt; using &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#writeSerializable(java.io.Serializable)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.writeSerializable()&lt;/code&gt;&lt;/a&gt; which is not the fastest implementation nor most compact representation. Some provide support for non-Parcelable types through custom adapters, but you still need to specify the adapter class in every place where you want to use it.&lt;/li&gt;
&lt;li&gt;These libraries usually serialize &lt;code&gt;Parcelable&lt;/code&gt; members inside &lt;code&gt;Parcelable&lt;/code&gt; classes using &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#writeParcelable(android.os.Parcelable,%20int)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.writeParcelable()&lt;/code&gt;&lt;/a&gt; which is less efficient to deserialize than using &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#writeTypedObject(T,%20int)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.writeTypedObject()&lt;/code&gt;&lt;/a&gt; when the concrete type is known.
This is because &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#readParcelable(java.lang.ClassLoader)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.readParcelable()&lt;/code&gt;&lt;/a&gt; first reads the full class name in order to retrieve the corresponding &lt;code&gt;Parcelable.Creator&lt;/code&gt; via &lt;strong&gt;reflection&lt;/strong&gt;, while &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#readTypedObject(android.os.Parcelable.Creator%3CT%3E)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcelable.readTypedObject()&lt;/code&gt;&lt;/a&gt; uses the provided &lt;code&gt;Parcelable.Creator&lt;/code&gt; directly.&lt;/li&gt;
&lt;li&gt;In some cases, I want the &lt;code&gt;Parcelable.Creator&lt;/code&gt; to act like a factory method determining which concrete sub-type will be created. Again, this is more efficient than using &lt;code&gt;Parcel.readParcelable()&lt;/code&gt;. I can’t do this if the &lt;code&gt;Parcelable.Creator&lt;/code&gt; is generated automatically.&lt;/li&gt;
&lt;li&gt;I like child classes to reuse &lt;code&gt;Parcelable&lt;/code&gt; code from their parent to avoid redundancy. This is not what most libraries do.&lt;/li&gt;
&lt;li&gt;Finally, almost all libraries slightly increase the &lt;strong&gt;methods count&lt;/strong&gt; of your APK file, because they bundle their own small runtime into your app and generate a few extra methods for each Parcelable class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to learn more about Parcelable libraries and their differences, I recommend this &lt;a href="https://blog.bradcampbell.nz/a-comparison-of-parcelable-boilerplate-libraries/" rel="noopener noreferrer"&gt;excellent article&lt;/a&gt; from Brad Campbell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kotlin for Parcelables
&lt;/h2&gt;

&lt;p&gt;Simply converting classes to the Kotlin programming language without any additional trick already makes them more readable than their Java equivalent.&lt;/p&gt;

&lt;p&gt;Consider the following example class written in Kotlin.&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;Person&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frdjc20e9bsrd0tifqeoh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frdjc20e9bsrd0tifqeoh.png" alt="Contextual action to generate a Parcelable implementation in Android Studio" width="410" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By using the built-in Android Studio contextual action to generate a &lt;code&gt;Parcelable&lt;/code&gt; implementation automatically, we get the following code:&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;Person&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readInt&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;writeToParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&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;describeContents&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;CREATOR&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Creator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&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;newArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;arrayOfNulls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&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;The result is &lt;strong&gt;26 lines&lt;/strong&gt; long.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cleaning up the generated code
&lt;/h3&gt;

&lt;p&gt;While the code quality is decent, you’ll notice that the &lt;code&gt;CREATOR&lt;/code&gt; static field has been implemented as the companion object of that class. This is technically working, but since a class is only allowed to have &lt;em&gt;a single companion object&lt;/em&gt;, it means you’ll have to add your class custom fields (like constants) directly into that &lt;code&gt;CREATOR&lt;/code&gt; object:&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;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;CREATOR&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Creator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;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;DEFAULT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"James"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&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;createFromParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&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;newArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;arrayOfNulls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&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;In addition, the Creator methods will be exposed as members of the Person class, polluting its API. This definitely doesn’t feel right and harms readability, so you’ll probably want to change the code to the recommended pattern which is to move the &lt;code&gt;CREATOR&lt;/code&gt; field &lt;em&gt;inside&lt;/em&gt; the companion object, and annotate it with &lt;a href="https://kotlinlang.org/docs/java-to-kotlin-interop.html#instance-fields" rel="noopener noreferrer"&gt;&lt;code&gt;@JvmField&lt;/code&gt;&lt;/a&gt; so it will be compiled to a static Java field:&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;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@JvmField&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;CREATOR&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;Parcelable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Creator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&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;newArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;arrayOfNulls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&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;We can also make the code a bit shorter by using &lt;a href="https://kotlinlang.org/docs/functions.html#single-expression-functions" rel="noopener noreferrer"&gt;single-expression functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, I like to use &lt;a href="https://kotlinlang.org/docs/functions.html#named-arguments" rel="noopener noreferrer"&gt;named arguments&lt;/a&gt; for more clarity when calling the primary constructor from the Parcel secondary constructor and make this constructor &lt;strong&gt;&lt;code&gt;private&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;protected&lt;/code&gt;&lt;/strong&gt; since only the &lt;code&gt;CREATOR&lt;/code&gt; and child classes will invoke it.&lt;/p&gt;

&lt;p&gt;We end up with the class looking like 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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readInt&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;writeToParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&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;describeContents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@JvmField&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;CREATOR&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;Parcelable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Creator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&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;newArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arrayOfNulls&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;size&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;It’s now &lt;strong&gt;22 lines&lt;/strong&gt; long.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. A better interface
&lt;/h3&gt;

&lt;p&gt;Like Java 8, Kotlin allows to add default implementations to &lt;a href="https://kotlinlang.org/docs/interfaces.html" rel="noopener noreferrer"&gt;interfaces&lt;/a&gt;. We can create an interface using this feature to provide the &lt;strong&gt;default implementation of the &lt;code&gt;describeContents()&lt;/code&gt; method&lt;/strong&gt;, which in 99.99% of cases should simply return 0 (and the cases where it should return another value are badly documented anyway). &lt;em&gt;Now we won’t have to write that useless method ever again.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We’ll also override the signature of the &lt;code&gt;writeToParcel()&lt;/code&gt; method to force its &lt;code&gt;Parcel&lt;/code&gt; argument to be &lt;strong&gt;non-null&lt;/strong&gt;, because it’s actually never null and you shouldn’t bother using the &lt;a href="https://kotlinlang.org/docs/null-safety.html#safe-calls" rel="noopener noreferrer"&gt;safe call operator&lt;/a&gt; on it.&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;interface&lt;/span&gt; &lt;span class="nc"&gt;KParcelable&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&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;describeContents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;writeToParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&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;From now on, we’ll simply make our objects implement &lt;code&gt;KParcelable&lt;/code&gt; instead of &lt;code&gt;Parcelable&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. A creator for &lt;code&gt;Creator&lt;/code&gt;s
&lt;/h3&gt;

&lt;p&gt;It’s time to leverage one of the most powerful features of the Kotlin language: higher order inline functions, which can be used like macros for code generation. In this case, we will write a function that generates implementations of these &lt;code&gt;Parcelable.Creator&lt;/code&gt; objects that always look the same.&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;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;reified&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;parcelableCreator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;crossinline&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;)&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;Parcelable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Creator&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&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;Parcel&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;source&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;newArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arrayOfNulls&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="n"&gt;size&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 is a modified version of the function provided by Juan Ignacio Saravia in his &lt;a href="https://medium.com/android-news/keddit-part-8-orientation-change-with-kotlin-parcelable-data-classes-f28136e8a6a8" rel="noopener noreferrer"&gt;instructive article&lt;/a&gt; about Parcelables in Kotlin.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://kotlinlang.org/docs/inline-functions.html#reified-type-parameters" rel="noopener noreferrer"&gt;reified generic type parameters&lt;/a&gt;, the &lt;code&gt;arrayOfNulls()&lt;/code&gt; function is able to create an array of the proper concrete type at compile time. This would not have been possible to achieve in Java without using reflection at runtime.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parcelableCreator()&lt;/code&gt; takes a single argument: a function returning a new instance of the target class from a non-null &lt;code&gt;Parcel&lt;/code&gt;. This argument can be a lambda, but it can also simply be a reference to a function like the class secondary constructor which takes a &lt;code&gt;Parcelable&lt;/code&gt; as argument:&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;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@JvmField&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;CREATOR&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parcelableCreator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Person&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;In addition, we can write a similar function to generate instances of &lt;a href="https://developer.android.com/reference/android/os/Parcelable.ClassLoaderCreator.html" rel="noopener noreferrer"&gt;&lt;code&gt;Parcelable.ClassLoaderCreator&lt;/code&gt;&lt;/a&gt; for cases where we need access to the &lt;code&gt;ClassLoader&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="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;reified&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;parcelableClassLoaderCreator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;crossinline&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ClassLoader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;)&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;Parcelable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ClassLoaderCreator&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&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;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ClassLoader&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loader&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;createFromParcel&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;Parcel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFromParcel&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;T&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classLoader&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;newArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arrayOfNulls&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="n"&gt;size&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;Our &lt;strong&gt;final class&lt;/strong&gt; has now been reduced to just &lt;strong&gt;16 lines&lt;/strong&gt; of code and is way more readable:&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;Person&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;KParcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readInt&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;writeToParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@JvmField&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;CREATOR&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parcelableCreator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Person&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;h3&gt;
  
  
  3. Extending Parcel
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Parcel&lt;/code&gt; only supports a handful of types to serialize. What if we could extend it to support more types, so that writing an &lt;code&gt;Enum&lt;/code&gt; to a Parcel would be as simple and as efficient as writing a &lt;code&gt;String&lt;/code&gt;? That’s exactly what Kotlin &lt;a href="https://kotlinlang.org/docs/extensions.html#extension-functions" rel="noopener noreferrer"&gt;extension functions&lt;/a&gt; are made for.&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;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;reified&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Enum&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;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readEnum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;readString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;enumValueOf&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="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="k"&gt;inline&lt;/span&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;:&lt;/span&gt; &lt;span class="nc"&gt;Enum&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;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeEnum&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="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;writeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can now write an &lt;code&gt;Enum&lt;/code&gt; to a &lt;code&gt;Parcel&lt;/code&gt; using this syntax:&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;dest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeEnum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Note how these extension functions use nullable types, so they can be used with &lt;strong&gt;both nullable and non-null&lt;/strong&gt; class members. The only compromise of this solution is that it forces you to use the &lt;a href="https://kotlinlang.org/docs/null-safety.html#the--operator" rel="noopener noreferrer"&gt;&lt;code&gt;!!&lt;/code&gt; operator&lt;/a&gt; when reading back a non-null value to a non-null member:&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;gender&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readEnum&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is safe since you know that the value written to the &lt;code&gt;Parcel&lt;/code&gt; was non-null in the first place. If somehow you get a null value here, it means that you made a huge mistake in your serializing code and the &lt;code&gt;NullPointerException&lt;/code&gt; is deserved.&lt;/p&gt;

&lt;p&gt;Another pair of useful &lt;code&gt;Parcel&lt;/code&gt; methods I mentioned earlier is &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#readTypedObject(android.os.Parcelable.Creator%3CT%3E)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.readTypedObject()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.android.com/reference/android/os/Parcel.html#writeTypedObject(T,%20int)" rel="noopener noreferrer"&gt;&lt;code&gt;Parcel.writeTypedObject()&lt;/code&gt;&lt;/a&gt; that should be preferred for reading or writing &lt;code&gt;Parcelable&lt;/code&gt; members when their concrete type is known. These methods are only available since API 23 and not yet part of the support library, but their implementation is straightforward. We can create compatibility versions working on any Android release using simple Kotlin extension functions:&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;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readTypedObjectCompat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Creator&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="nf"&gt;readNullable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFromParcel&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="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;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeTypedObjectCompat&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="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;writeNullable&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="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="nf"&gt;writeToParcel&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="n"&gt;flags&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;Note that I extracted the null handling parts of the code to external inline functions &lt;code&gt;readNullable()&lt;/code&gt; and &lt;code&gt;writeNullable()&lt;/code&gt; so they can be reused by other utility functions.&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;inline&lt;/span&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="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&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="nf"&gt;readInt&lt;/span&gt;&lt;span class="p"&gt;()&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="nf"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

&lt;span class="k"&gt;inline&lt;/span&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="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeNullable&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="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&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;value&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="nf"&gt;writeInt&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="nf"&gt;writer&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;writeInt&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can find a complete set of useful extension functions for &lt;code&gt;Parcel&lt;/code&gt; in the full source code listing at the end of this article.&lt;/p&gt;

&lt;p&gt;As a last example, these function calls can be grouped with &lt;code&gt;apply()&lt;/code&gt;, &lt;code&gt;run()&lt;/code&gt; or &lt;code&gt;with()&lt;/code&gt; to reduce the verbosity to a minimum:&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;writeToParcel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;writeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;writeInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;writeEnum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;writeDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;birthDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;writeTypedObjectCompat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpytxpdfgxbb7gr5792lw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpytxpdfgxbb7gr5792lw.jpg" alt="Neo in The Matrix saying " width="566" height="333"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Full source code of the Parcelable utilities
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The Kotlin language itself is a powerful tool to reduce boilerplate code in &lt;code&gt;Parcelable&lt;/code&gt; classes. For those who want full control over the serialization process with minimum overhead while keeping the code as readable as possible, this set of Kotlin utilities and best practices is a good alternative to Parcelable libraries.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As always, please share if you like. Thank you for reading!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>androiddev</category>
      <category>android</category>
    </item>
    <item>
      <title>Fixing ugly Java APIs: read-only generic varargs and how Kotlin generic types are superior to Java’s</title>
      <dc:creator>Christophe Beyls</dc:creator>
      <pubDate>Thu, 29 Jun 2017 22:00:00 +0000</pubDate>
      <link>https://dev.to/cbeyls/fixing-ugly-java-apis-read-only-generic-varargs-and-how-kotlin-generic-types-are-superior-to-javas-2db1</link>
      <guid>https://dev.to/cbeyls/fixing-ugly-java-apis-read-only-generic-varargs-and-how-kotlin-generic-types-are-superior-to-javas-2db1</guid>
      <description>&lt;p&gt;There is an Android API I hate using because of a specific confusing method call. I’m certain there are many other examples of similar methods in the Java world. What’s interesting about it is that it illustrates how the limitations of a programming language (Java in this case) can lead to forcing developers to write unnecessarily cryptic code &lt;strong&gt;just to call a single method&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s also a good opportunity to explore &lt;strong&gt;the obscure world of generic types and variance&lt;/strong&gt; that even experienced developers often struggle to fully understand.&lt;/p&gt;

&lt;p&gt;While I’ll be using the Android platform as an example, the problems described hereafter apply to any Java code.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problematic method
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/reference/android/app/ActivityOptions.html#makeSceneTransitionAnimation(android.app.Activity,%20android.util.Pair%3Candroid.view.View,%20java.lang.String%3E...)" rel="noopener noreferrer"&gt;The Java method I want to discuss&lt;/a&gt; is part of the Android API designed to launch &lt;a href="https://developer.android.com/training/material/animations.html#Transitions" rel="noopener noreferrer"&gt;Activity transitions&lt;/a&gt; with shared elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ActivityOptions&lt;/span&gt; &lt;span class="nf"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;...&lt;/span&gt; &lt;span class="n"&gt;sharedElements&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;a href="https://developer.android.com/reference/android/support/v4/app/ActivityOptionsCompat.html#makeSceneTransitionAnimation(android.app.Activity,%20android.support.v4.util.Pair%3Candroid.view.View,%20java.lang.String%3E...)" rel="noopener noreferrer"&gt;similar method&lt;/a&gt; is also available in the Android support library. A typical call forces me to write code looking like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SuppressWarnings&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unchecked"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ActivityOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem2"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toBundle&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not so pretty. There are 2 reasons why this method call is made difficult.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Arrays of generic types are unsafe
&lt;/h2&gt;

&lt;p&gt;The first problem you’ll notice is that, no matter which arguments you pass to this method, &lt;strong&gt;the compiler will always show a warning message&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Compiles with warning:&lt;/span&gt;
&lt;span class="c1"&gt;// "unchecked generics array creation for varargs parameter"&lt;/span&gt;
&lt;span class="nc"&gt;ActivityOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elem1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elem2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason behind that warning is that &lt;a href="https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#createArrays" rel="noopener noreferrer"&gt;&lt;strong&gt;Java does not allow creating arrays of parameterized types&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Does NOT compile&lt;/span&gt;
&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Compiles with warning: "Unchecked assignment"&lt;/span&gt;
&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is forbidden because &lt;strong&gt;Java arrays are covariant&lt;/strong&gt; and they check the type of values written to them at runtime. But at runtime, &lt;a href="https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html" rel="noopener noreferrer"&gt;generic types have been erased&lt;/a&gt; and the array can not differentiate a &lt;code&gt;Pair&amp;lt;View, String&amp;gt;&lt;/code&gt; from a &lt;code&gt;Pair&amp;lt;Integer, Integer&amp;gt;&lt;/code&gt;, leading to potential &lt;a href="https://en.wikipedia.org/wiki/Heap_pollution" rel="noopener noreferrer"&gt;heap pollution&lt;/a&gt; and breaking the array contract.&lt;/p&gt;

&lt;p&gt;When you call a method with &lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html" rel="noopener noreferrer"&gt;a variable number of arguments&lt;/a&gt;, an array is created to pass all the arguments and since the type of that array can not be parameterized, an &lt;strong&gt;unchecked assignment&lt;/strong&gt; has to be made.&lt;/p&gt;

&lt;p&gt;To sum it up, as soon as you want to put generic types in a Java array, you’re on your own to guarantee the safety of your code and to prevent a &lt;code&gt;ClassCastException&lt;/code&gt; from occurring at runtime. This is why &lt;strong&gt;collections should be preferred to arrays when dealing with generic types in Java&lt;/strong&gt;. Changing the method signature to use a &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; instead of &lt;code&gt;T...&lt;/code&gt; would avoid compiler warnings and guarantee type safety at compile time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elem1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elem2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;ActivityOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, it would also make the method call even more verbose and we don’t want that either.&lt;/p&gt;

&lt;h3&gt;
  
  
  The fix: &lt;code&gt;@SafeVarargs&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The recommended way to fix the variable arguments declaration is to add the &lt;a href="https://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html" rel="noopener noreferrer"&gt;&lt;code&gt;@SafeVarargs&lt;/code&gt;&lt;/a&gt; annotation (available since Java 7) to the method signature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SafeVarargs&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ActivityOptions&lt;/span&gt; &lt;span class="nf"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;...&lt;/span&gt; &lt;span class="n"&gt;sharedElements&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;strong&gt;prevents the compiler from issuing a warning&lt;/strong&gt; when calling the method with the &lt;strong&gt;multiple arguments syntax&lt;/strong&gt; (not passing a single array reference). Adding this annotation tells the compiler that we guarantee that the body of this method only expects each argument in the varargs array to be of the exact declared type and will not perform potentially unsafe operations on it.&lt;/p&gt;

&lt;p&gt;On the caller side, when the method is called with this syntax, we rely on the compiler to generate an array populated with objects of the exact same type as well.&lt;/p&gt;

&lt;p&gt;Overall this solution feels like a hack, but that’s the best we can get with varargs using the Java language. It’s preferable to add this annotation once on your public API methods, rather than forcing developers to add &lt;code&gt;@SuppressWarnings("unchecked")&lt;/code&gt; annotations above each method call.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Read-only arguments of generic types should not be invariant
&lt;/h2&gt;

&lt;p&gt;The second problem with this method is the &lt;strong&gt;overly restrictive type of the &lt;code&gt;Pair&lt;/code&gt; arguments&lt;/strong&gt;. The &lt;code&gt;Pair&lt;/code&gt; class is actually &lt;strong&gt;read-only&lt;/strong&gt; by nature because its two fields are &lt;code&gt;final&lt;/code&gt;, so it would be perfectly reasonable to provide for example a &lt;code&gt;Pair&amp;lt;TextView, String&amp;gt;&lt;/code&gt; as argument and not only strict instances of &lt;code&gt;Pair&amp;lt;View, String&amp;gt;&lt;/code&gt; (&lt;code&gt;TextView&lt;/code&gt; inherits from &lt;code&gt;View&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Suppose I previously declared a variable of type &lt;code&gt;TextView&lt;/code&gt; and I want to pass it in the &lt;code&gt;Pair&lt;/code&gt; arguments. In order to write shorter code, I tend to always use the &lt;a href="https://developer.android.com/reference/android/util/Pair.html#create(A,%20B)" rel="noopener noreferrer"&gt;&lt;code&gt;Pair.create()&lt;/code&gt;&lt;/a&gt; generic factory method which allows creating a parameterized &lt;code&gt;Pair&amp;lt;A, B&amp;gt;&lt;/code&gt; instance without having to specify the types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Creates a Pair&amp;lt;TextView, String&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Creates a Pair&amp;lt;View, String&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Creates a Pair&amp;lt;View, String&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first syntax is the shortest but can’t be used here because unlike arrays, &lt;strong&gt;Java generic types are always invariant by default&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Does NOT compile: incompatible types&lt;/span&gt;
&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elem1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The fix: wildcards declaration
&lt;/h3&gt;

&lt;p&gt;Fortunately, there is a way to make a generic type covariant in Java: using &lt;a href="https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html" rel="noopener noreferrer"&gt;&lt;strong&gt;wildcards&lt;/strong&gt;&lt;/a&gt; in the type declaration. This is called &lt;strong&gt;use-site variance&lt;/strong&gt; because it has to be specified in the type of &lt;strong&gt;each variable&lt;/strong&gt; where you want to use covariance (read-only generic parameters) or contravariance (write-only generic parameters).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Compiles (View type can only be consumed)&lt;/span&gt;
&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elem1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Declaring wildcards&lt;/strong&gt; for read-only or write-only generic arguments in methods of public APIs &lt;strong&gt;should be systematic&lt;/strong&gt;. But they are easy to forget, especially for those who are not too familiar with variance and generic types.&lt;/p&gt;

&lt;p&gt;Here is the final fixed signature of our Java method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SafeVarargs&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ActivityOptions&lt;/span&gt; &lt;span class="nf"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;...&lt;/span&gt; &lt;span class="n"&gt;sharedElements&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now our caller code gets simpler with less room for errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ActivityOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageView&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem2"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toBundle&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cleaner APIs using Kotlin
&lt;/h2&gt;

&lt;p&gt;If that method had been written in Kotlin, &lt;strong&gt;those 2 limitations would have been avoided entirely&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyzk3fqmgqyk3dma5auka.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyzk3fqmgqyk3dma5auka.jpg" alt="Kotlin ketchup: A programming language with 60% less calories." width="700" height="700"&gt;&lt;/a&gt;&lt;/p&gt;
A programming language with 60% less calories.



&lt;h3&gt;
  
  
  Kotlin arrays are safer
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Kotlin arrays&lt;/strong&gt; are different from Java arrays: they behave just like standard classes and are invariant by default. This means that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The compiler guarantees &lt;strong&gt;compile-time type safety for arrays&lt;/strong&gt; as well;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arrays of parameterized types are allowed&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No compiler warning&lt;/strong&gt; will be shown when calling a method with a variable number of parameterized arguments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Furthermore, &lt;strong&gt;variable arguments arrays&lt;/strong&gt; are declared as &lt;strong&gt;covariant&lt;/strong&gt; automatically, which makes them read-only inside the varargs function.&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;someFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;vararg&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Does NOT compile: read-only&lt;/span&gt;
        &lt;span class="n"&gt;words&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="s"&gt;"Test"&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;&lt;strong&gt;Use-site variance&lt;/strong&gt; is supported in Kotlin as well, but instead of complicated wildcards, &lt;a href="https://kotlinlang.org/docs/generics.html#type-projections" rel="noopener noreferrer"&gt;&lt;strong&gt;type projections&lt;/strong&gt;&lt;/a&gt; are used. This is done using the &lt;strong&gt;&lt;code&gt;out&lt;/code&gt;&lt;/strong&gt; (read-only types) and &lt;strong&gt;&lt;code&gt;in&lt;/code&gt;&lt;/strong&gt; (write-only types) keywords.&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="c1"&gt;// Type-safe universal array copy function&lt;/span&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;copy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;out&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="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;in&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="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&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;h3&gt;
  
  
  Declaration-site variance is easier
&lt;/h3&gt;

&lt;p&gt;But the real killer feature of Kotlin regarding generic types is the added ability to declare variance of generic types &lt;strong&gt;directly in a parameterized class or interface&lt;/strong&gt;. This is called &lt;a href="https://kotlinlang.org/docs/generics.html#declaration-site-variance" rel="noopener noreferrer"&gt;&lt;strong&gt;declaration-site variance&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Kotlin provides its own &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-pair/" rel="noopener noreferrer"&gt;&lt;code&gt;Pair&lt;/code&gt;&lt;/a&gt; class which uses this feature.&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;data class&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="nc"&gt;B&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;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;A&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;second&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because both values passed in the constructor are read-only, their type can be declared as covariant using the &lt;code&gt;out&lt;/code&gt; keyword. Then the parameters of the &lt;code&gt;Pair&amp;lt;A, B&amp;gt;&lt;/code&gt; class will &lt;strong&gt;always be covariant&lt;/strong&gt;, no matter where it’s used. Variance only has to be declared &lt;strong&gt;once&lt;/strong&gt; inside the class, eliminating the risk of forgetting to declare it in every public method signature using that class.&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="c1"&gt;// Creates a Pair&amp;lt;TextView, String&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;pair&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// OK: it's covariant by default&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;elem1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&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;pair&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Our method in a Kotlin world
&lt;/h3&gt;

&lt;p&gt;Due to the language features described above, our API method could have been written like the following extension function:&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="nc"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;vararg&lt;/span&gt; &lt;span class="n"&gt;sharedElements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ActivityOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no need to add annotations or specify variance for the &lt;code&gt;Pair&lt;/code&gt; parameters because the language does the right thing by default. We also get null safety for free.&lt;/p&gt;

&lt;p&gt;Finally, calling this function from Kotlin code would be even more readable than the fixed Java version, partly thanks to the &lt;a href="https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/to.html" rel="noopener noreferrer"&gt;sweeter syntax&lt;/a&gt; to create &lt;code&gt;Pair&lt;/code&gt; objects:&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;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeSceneTransitionAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;textView&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"elem1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;imageView&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"elem2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBundle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;This concludes this small demonstration of the benefits of the Kotlin approach to generic types and how the language helps you write cleaner and safer code by default. I hope you learned a few things and as always, please share if you like.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>java</category>
      <category>generics</category>
      <category>arrays</category>
    </item>
  </channel>
</rss>
