<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.2">Jekyll</generator><link href="https://andrewbailey.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://andrewbailey.dev/" rel="alternate" type="text/html" /><updated>2022-12-19T20:48:02-05:00</updated><id>https://andrewbailey.dev/feed.xml</id><title type="html">Andrew Bailey</title><subtitle>Personal website</subtitle><entry><title type="html">Kotlin Book Announcement!</title><link href="https://andrewbailey.dev/post/2021/09/14/kotlin-2e" rel="alternate" type="text/html" title="Kotlin Book Announcement!" /><published>2021-09-14T17:00:00-04:00</published><updated>2021-10-05T12:00:00-04:00</updated><id>https://andrewbailey.dev/post/2021/09/14/kotlin-2e</id><content type="html" xml:base="https://andrewbailey.dev/post/2021/09/14/kotlin-2e">&lt;p&gt;Earlier this year, I got an opportunity to work on Big Nerd Ranch’s acclaimed Guide to Kotlin Programming.
David and Josh, the authors of the first edition, had already put together a great set of materials, and it was an exciting task to update them for the next generation of Kotlin learners.&lt;/p&gt;

&lt;p&gt;Now that we’re inches away from crossing the finish line, I’m thrilled to tell you all about the second edition of &lt;em&gt;Kotlin Programming: The Big Nerd Ranch Guide&lt;/em&gt;.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/post/2021-09-14-kotlin-2e/cover.jpg&quot; width=&quot;250px&quot; style=&quot;float: left; margin-right: 16px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The second edition of the book has a number of improvements since its first installation.
First, we’ve updated our materials for Kotlin 1.5 and IntelliJ 2021.2.
We’ve also added new material to cover the latest and greatest features in Kotlin, including Kotlin Multiplatform, Coroutines, Channels, Flows, inline classes, and unsigned numeric types.
If you’ve been thinking about learning Kotlin and want a step-by-step guide to walk you through the language, then look no further.&lt;/p&gt;

&lt;p&gt;For more information about the book, check out &lt;a href=&quot;https://bignerdranch.com/blog/coming-soon-kotlin-programming-the-big-nerd-ranch-guide-second-edition/&quot;&gt;Big Nerd Ranch’s official announcement&lt;/a&gt; of the second edition.
You can also learn more about Big Nerd Ranch’s &lt;a href=&quot;https://bignerdranch.com/books/&quot;&gt;other books&lt;/a&gt; if you’re interested in learning more beyond Kotlin.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Kotlin Programming: The Big Nerd Ranch Guide&lt;/em&gt;, Second Edition is available right now on &lt;a href=&quot;https://www.amazon.com/Kotlin-Programming-Ranch-Guide-Guides/dp/0136891055&quot;&gt;Amazon&lt;/a&gt; in Kindle format and will be making its way to other eBook retailers soon.
Printed copies will be available starting late October.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;</content><author><name>Andrew Bailey</name></author><category term="Android" /><category term="Kotlin" /><summary type="html">Earlier this year, I got an opportunity to work on Big Nerd Ranch’s acclaimed Guide to Kotlin Programming. David and Josh, the authors of the first edition, had already put together a great set of materials, and it was an exciting task to update them for the next generation of Kotlin learners. Now that we’re inches away from crossing the finish line, I’m thrilled to tell you all about the second edition of Kotlin Programming: The Big Nerd Ranch Guide.</summary></entry><entry><title type="html">Falsehoods Android Developers Believe about Lifecycles</title><link href="https://andrewbailey.dev/falsehoods/lifecycles" rel="alternate" type="text/html" title="Falsehoods Android Developers Believe about Lifecycles" /><published>2020-07-30T12:00:00-04:00</published><updated>2020-07-30T12:00:00-04:00</updated><id>https://andrewbailey.dev/falsehoods/fadbal</id><content type="html" xml:base="https://andrewbailey.dev/falsehoods/lifecycles">&lt;p&gt;Lifecycles are what drive your Android apps, but developers often overlook edge cases that lead to lost user inputs and mysterious crashes.
This talk will focus on assumptions that you might be making in your Activities and Fragments, where those assumptions fall apart, and what you should do to avoid deviously subtle lifecycle-related issues in your apps. 
These are details that trip up both junior and experienced developers, so regardless of your experience, this talk will bring a new perspective to how you think about lifecycles.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;watch-the-talk&quot;&gt;Watch the Talk&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.droidcon.com/media-detail?video=443146897&quot;&gt;&lt;img src=&quot;/assets/img/fadbal.jpg&quot; alt=&quot;Presentation Thumbnail&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you to everyone who tuned in live to the Droidcon Online webinar to listen to this talk!
If you missed the talk or need a quick refresher on anything I went over, you can find the recording on &lt;a href=&quot;https://www.droidcon.com/media-detail?video=443146897&quot;&gt;Droidcon’s website&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;get-the-cheat-sheet&quot;&gt;Get the Cheat-Sheet&lt;/h2&gt;
&lt;p&gt;This talk goes over a lot of information very quickly.
To help you remember these details, I’ve condensed most of information into a single cheat-sheet that you can use as a quick reference.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/raw/lifecycles-cheat-sheet.pdf&quot;&gt;Download the Cheat-Sheet&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;

&lt;h3 id=&quot;incrementer&quot;&gt;Incrementer&lt;/h3&gt;
&lt;p&gt;Incrementer is an app I built to demonstrate the most common ways that Android developers are handling Activity recreations.
This ranges from best practices to less recommended techniques.
You can use Incrementer to see firsthand the benefits and shortcomings of each technique.
The code for Incrementer and more information about how each implementation behaves is available on &lt;a href=&quot;https://github.com/andrewbailey/Incrementer&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;venom&quot;&gt;Venom&lt;/h3&gt;
&lt;p&gt;Venom is a library (not created by me) that can help you test process death scenarios.
It can display a persistent notification to you or your QA team that can directly trigger process death without the need to run your app through Android Studio.
You can find the library on &lt;a href=&quot;https://github.com/YarikSOffice/venom&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;sources&quot;&gt;Sources&lt;/h3&gt;
&lt;p&gt;For many of the topics I discussed, the information presented has come from first-hand experiences and testing with various situations.
For more lower-level operating system behaviors, I have incorporated information from the Android developer documentation.&lt;/p&gt;

&lt;p&gt;I’ve linked these sources below both to provide more credibility to this advice and to provide a starting point if you’d like to research these details in more depth.&lt;/p&gt;

&lt;h4 id=&quot;androidconfigchanges-attribute&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;android:configChanges&lt;/code&gt; Attribute&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Should only be used when you must avoid restarts caused by a configuration change&lt;/li&gt;
  &lt;li&gt;Not recommended for most applications&lt;/li&gt;
  &lt;li&gt;Your app must be able to restart and save its state&lt;/li&gt;
  &lt;li&gt;This should not be used as a technique to avoid saving state against the normal lifecycle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Source:&lt;/em&gt; &lt;a href=&quot;https://developer.android.com/guide/topics/resources/runtime-changes#HandlingTheChange&quot;&gt;Handling Configuration Changes Guide&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;handling-process-death&quot;&gt;Handling Process Death&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Memory pressure requires the system to release memory&lt;/li&gt;
  &lt;li&gt;Methods of freeing memory include killing processes&lt;/li&gt;
  &lt;li&gt;The exact behavior is device-specific and very customizable&lt;/li&gt;
  &lt;li&gt;ViewModels do not survive process death&lt;/li&gt;
  &lt;li&gt;You should still use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SavedStateHandle&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onSaveInstanceState()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;ViewModels do still have a purpose because they can prevent redundant database or network calls after a configuration change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Sources:&lt;/em&gt; &lt;a href=&quot;https://developer.android.com/topic/libraries/architecture/saving-states#use_onsaveinstancestate_as_backup_to_handle_system-initiated_process_death&quot;&gt;Saving States Architecture Topic&lt;/a&gt;, &lt;a href=&quot;https://source.android.com/devices/tech/perf/lmkd&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lmkd&lt;/code&gt; (Viking Killer) Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;bundle--intent-size-limitations&quot;&gt;Bundle &amp;amp; Intent size limitations&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Android has a theoretical limit of 1MB when sending data between processes&lt;/li&gt;
  &lt;li&gt;On Android 7.0+, TransactionTooLargeException is thrown while starting the activity (not when creating the Intent)&lt;/li&gt;
  &lt;li&gt;On older versions, a warning is sent to logcat&lt;/li&gt;
  &lt;li&gt;“We recommend that you keep saved state to less than 50k of data.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Source:&lt;/em&gt; &lt;a href=&quot;https://developer.android.com/guide/components/activities/parcelables-and-bundles#sdbp&quot;&gt;Parcelables &amp;amp; Bundles Guide&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;backup-behavior&quot;&gt;Backup behavior&lt;/h4&gt;
&lt;blockquote&gt;
  &lt;p&gt;During auto backup and restore operations, the system launches the app in a restricted mode to both prevent the app from accessing files that could cause conflicts and let the app execute callback methods in its BackupAgent. 
In this restricted mode, the app’s main activity is not automatically launched, its Content Providers are not initialized, and the base-class Application is instantiated instead of any subclass declared in the app’s manifest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Sources:&lt;/em&gt; &lt;a href=&quot;https://developer.android.com/guide/topics/data/testingbackup#Troubleshooting&quot;&gt;Testing Backup Guide&lt;/a&gt;, &lt;a href=&quot;https://developer.android.com/guide/topics/data/autobackup#ImplementingBackupAgent&quot;&gt;BackupAgent Guide&lt;/a&gt;&lt;/p&gt;</content><author><name></name></author><category term="Talks" /><summary type="html">Lifecycles are what drive your Android apps, but developers often overlook edge cases that lead to lost user inputs and mysterious crashes. This talk will focus on assumptions that you might be making in your Activities and Fragments, where those assumptions fall apart, and what you should do to avoid deviously subtle lifecycle-related issues in your apps. These are details that trip up both junior and experienced developers, so regardless of your experience, this talk will bring a new perspective to how you think about lifecycles.</summary></entry><entry><title type="html">Debuting Difference</title><link href="https://andrewbailey.dev/post/2020/07/06/difference" rel="alternate" type="text/html" title="Debuting Difference" /><published>2020-07-06T16:00:00-04:00</published><updated>2020-07-06T16:00:00-04:00</updated><id>https://andrewbailey.dev/post/2020/07/06/difference</id><content type="html" xml:base="https://andrewbailey.dev/post/2020/07/06/difference">&lt;p&gt;I recently published &lt;a href=&quot;https://github.com/andrewbailey/Difference&quot;&gt;Difference&lt;/a&gt;, a Kotlin library that lets you compare two lists to determine a sequence of change operations between the two.
Many Android developers have already been generating diffs to animate changes in their RecyclerViews, but there are many other reasons you might want to compare two lists.
Maybe you’re working on an app that needs to detect differences between two files like git does.
Or maybe a backend you’re integrating with sends you a before and after state, but your app needs to show only what changed.&lt;/p&gt;

&lt;p&gt;Regardless of your use-case, Difference is here to help.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;why-not-use-diffutil&quot;&gt;Why not use DiffUtil?&lt;/h2&gt;
&lt;p&gt;The first question you’re probably asking is, “Why on earth would you make a list diffing library? You’re an Android developer and Google already made &lt;a href=&quot;https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil&quot;&gt;DiffUtil&lt;/a&gt;.”
I could answer this question by saying “Because I am insane and like making things more complicated than they need to be,” and while that accounts for most of my decisions in general, it avoids the bigger picture here.&lt;/p&gt;

&lt;p&gt;If you’re using DiffUtil with a RecyclerView and you don’t have a need for diffs in any other context, then everything is great and you should keep using DiffUtil.
But the big problem with DiffUtil is that it’s coupled with RecyclerView, and that has some serious drawbacks for other use cases.&lt;/p&gt;

&lt;h3 id=&quot;diffutil-is-not-cross-platform&quot;&gt;DiffUtil is not cross-platform&lt;/h3&gt;
&lt;p&gt;DiffUtil is a Java library that has a dependency on RecyclerView.
Those two facts already limit its usage to the universe of Android app projects.
Even if you coerce your compiler and coworkers to let you use DiffUtil with a vanilla Java project, that’s as much cross-compatibility you’ll get from it.
This is especially unfortunate because the diffing algorithm at its core has no Android or even Java dependencies to function properly.&lt;/p&gt;

&lt;p&gt;This is where Difference comes in.
Difference is a Kotlin multiplatform library that’s platform independent.
Regardless of if you’re developing for web, native, Android or iOS, you can use Difference in your project — which you can’t say about DiffUtil.&lt;/p&gt;

&lt;h3 id=&quot;diffutil-depends-on-recyclerview&quot;&gt;DiffUtil depends on RecyclerView&lt;/h3&gt;
&lt;p&gt;DiffUtil is included as part of the RecyclerView library, meaning that if you want DiffUtil you also need to pull in RecyclerView.
The real issue is that if you’re bringing in RecyclerView, you also end up pulling in the entire universe that is the appcompat library.&lt;/p&gt;

&lt;p&gt;For many apps this isn’t a big deal whatsoever.
After all, you’re likely already using RecyclerView, so what’s the big deal with some clever reuse of DiffUtil since we already know how to use it?&lt;/p&gt;

&lt;p&gt;But if you step into your DeLorean with me for a moment and visit the year 2021 or 2022, you’ll be seeing Jetpack Compose in a lot of places.
(Or so we can hope.
My crystal ball doesn’t keep me in the loop about software release dates and adoption rates.)&lt;/p&gt;

&lt;p&gt;If you’re building an app that uses Jetpack Compose, you probably don’t want to be bringing in RecyclerView for the sake of getting DiffUtil.
In this utopian future, adding RecyclerView to your project means pulling in a lot of code centered around a UI framework that you have no intention of using.
R8 can minify these classes away for you, but that means adding a lot of unnecessary complexity to your build pipeline to make sure you’re not bloating your APK size with code you’ll never use.
It’s much easier if you never add RecyclerView to your project to begin with if your app exclusively uses Compose.
If you’re one of these lucky full-time composers, then Difference is for you.&lt;/p&gt;

&lt;h2 id=&quot;how-does-difference-compare-to-diffutil&quot;&gt;How does Difference compare to DiffUtil?&lt;/h2&gt;
&lt;p&gt;Difference is a Kotlin multiplatform library that implements Eugene Myers’ differencing algorithm — the same algorithm that DiffUtil implements.
Difference will detect insertions, deletions, and (optionally) moves.
It also uses similar optimizations as DiffUtil to avoid recursion and to reduce the amount of memory allocated by the algorithm.&lt;/p&gt;

&lt;p&gt;If you like big-O notation, the worst case runtime of the algorithm takes on the order of O((M+N)×D + D log D) operations.
M and N are the lengths of the two input lists, and D is the smallest number of operations that it takes to modify the original list into the updated one.
If move detection is enabled, add another O(D²) to that runtime.&lt;/p&gt;

&lt;p&gt;Difference is written from the ground-up for Kotlin — which is to say that I did not open DiffUtil, press ⌘+⇧+K, and call it a day.
It takes advantage of Kotlin language features like lambda expressions and default parameters to allow for concise code.
It does not use any external dependencies, and can be compiled to run on any platform that can run Kotlin code.&lt;/p&gt;

&lt;h2 id=&quot;start-using-difference&quot;&gt;Start using Difference&lt;/h2&gt;
&lt;p&gt;If I’ve kept your attention thus far, then you’re likely one of the lucky individuals with a use case for Difference.
If you’re using Gradle, you can use this line to add Difference to your project:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;implementation&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dev.andrewbailey.difference:difference:1.0.0&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When you need to compute a diff for two sets of data, you can call Difference like this:&lt;/p&gt;
&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;listOfBffs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;listOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Merengue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Sherb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Tammy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;revisedListOfBffs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;listOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Merengue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Sprinkle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Sherb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;differenceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listOfBffs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;updated&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;revisedListOfBffs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;detectMoves&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The returned &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff&lt;/code&gt; object will contain a list of operations that, when applied in order on the original list, will yield the updated list.
In the example above, the diff would look like this:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Insert(index = 1, item = &quot;Sprinkle&quot;)
Remove(index = 3)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you’re building a UI-based application, be careful when using Difference since diff generation can easily exceed 16ms for arbitrary lists which can lead to dropped frames.
Because of the runtime complexity of diff generation, I highly recommend using Difference on a background thread to keep your UI smooth.
If you’re using Coroutines, then you can easily offload diff generation to a background thread like this:&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;launch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;listOfBffs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;revisedListOfBffs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;withContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Dispatchers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;differenceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Do whatever you need with the diff&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;applyDiff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;remove&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oldIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newIndex&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can find the source code and documentation for Difference &lt;a href=&quot;https://github.com/andrewbailey/Difference&quot;&gt;on GitHub&lt;/a&gt;.
Give it a shot the next time you need to compare two lists and let me know what you think!&lt;/p&gt;</content><author><name>Andrew Bailey</name></author><category term="Android" /><summary type="html">I recently published Difference, a Kotlin library that lets you compare two lists to determine a sequence of change operations between the two. Many Android developers have already been generating diffs to animate changes in their RecyclerViews, but there are many other reasons you might want to compare two lists. Maybe you’re working on an app that needs to detect differences between two files like git does. Or maybe a backend you’re integrating with sends you a before and after state, but your app needs to show only what changed. Regardless of your use-case, Difference is here to help.</summary></entry></feed>