<?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: Nicholas Fragiskatos</title>
    <description>The latest articles on DEV Community by Nicholas Fragiskatos (@nfragiskatos).</description>
    <link>https://dev.to/nfragiskatos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1187468%2Fb992c022-c817-413d-8e6f-b7ea723732be.jpg</url>
      <title>DEV Community: Nicholas Fragiskatos</title>
      <link>https://dev.to/nfragiskatos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nfragiskatos"/>
    <language>en</language>
    <item>
      <title>How to Use Memoization in React for Better Performance</title>
      <dc:creator>Nicholas Fragiskatos</dc:creator>
      <pubDate>Thu, 16 May 2024 03:27:13 +0000</pubDate>
      <link>https://dev.to/nfragiskatos/how-to-use-memoization-in-react-for-better-performance-1277</link>
      <guid>https://dev.to/nfragiskatos/how-to-use-memoization-in-react-for-better-performance-1277</guid>
      <description>&lt;p&gt;Memoization, not memorization, is a technique commonly used in functional programming to improve performance of an application. To put it simply, memoization is just caching the result of a function, then whenever that function is invoked again, as long the inputs are the same, the cached result can be returned instead of re-running the function. It is important to note that the memoized function would need to be a &lt;em&gt;pure&lt;/em&gt; function. That is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The returned value is always the same for an identical set of inputs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The function does note mutate state outside of its scope, i.e., there are no side-effects.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;React, which heavily encourages the use of a functional style of programming, naturally provides its own mechanisms for developers to optimize their application through memoization. With &lt;code&gt;React.memo(...)&lt;/code&gt;, &lt;code&gt;useCallback(...)&lt;/code&gt;, and &lt;code&gt;useMemo(...)&lt;/code&gt;, developers can have finer control over their application to prevent unnecessary re-rendering of components or heavy recalculations of data.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;React.memo(...)&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The purpose of &lt;code&gt;React.memo(...)&lt;/code&gt; is to prevent unwanted re-rendering of a child component if its props have not changed when the parent component is re-rendered.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Consider this &lt;code&gt;&amp;lt;Parent/&amp;gt;&lt;/code&gt; component. It contains a button that, when clicked, increments a &lt;code&gt;total&lt;/code&gt; state variable and it displays the current value of &lt;code&gt;total&lt;/code&gt;. Lastly, it contains a &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt; component that does not take any props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Child&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-col gap-1 w-1/5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 bg-cyan-600 p-1 border-black rounded-md text-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increment&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt; component only displays how many times it has been rendered. There's a &lt;code&gt;useRef(...)&lt;/code&gt; paired with a &lt;code&gt;useEffect(...)&lt;/code&gt; that keeps track of the number of renders for the component, and it displays that count.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Child Rendered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;renderCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;renderCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Render&lt;/span&gt; &lt;span class="na"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All together these two components create this UI&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gl8w_FyF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715828304793/b8b1aeeb-fa52-4abd-89e6-6e149c59a67c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gl8w_FyF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715828304793/b8b1aeeb-fa52-4abd-89e6-6e149c59a67c.png" alt="Picture of UI" width="541" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see what happens when we press the button to increment the &lt;code&gt;total&lt;/code&gt; state variable of the parent component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q8K9XJMG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715828426837/51de88e3-8626-45c6-bd9e-2e6265d32410.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q8K9XJMG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715828426837/51de88e3-8626-45c6-bd9e-2e6265d32410.gif" alt="Gif showing child component re-rendering when parent re-renders" width="464" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The child component re-renders with the parent component. This seems odd, especially since the child component's props are not changing. In fact, it does not even have any props.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;Fortunately, the solution is simple; wrap the child component in &lt;code&gt;React.memo(Component, proprsComparatorFunction)&lt;/code&gt;. Now when the parent component re-renders the child component does not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// import&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// wrapping component&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--12_U6EQk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715828544258/fc31b99c-2b57-45a0-8601-e40e9e7e028b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--12_U6EQk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715828544258/fc31b99c-2b57-45a0-8601-e40e9e7e028b.gif" alt="Gif showing how React.memo prevents the child component re-rendering when the parent component re-renders" width="464" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The Comparator Function
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;React.memo(...)&lt;/code&gt; has a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"&gt;second argument&lt;/a&gt; for a comparator function, which wasn't utilized in the example. By default, if no function is specified, then React will do a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"&gt;&lt;em&gt;shallow&lt;/em&gt; comparison&lt;/a&gt; of the previous and new prop values. A shallow comparison is fine if using simple data types like comparing numbers or booleans, but if the prop is something more complex like an object, then a custom implementation might be necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useCallback(...)&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The purpose of &lt;code&gt;useCallback(...)&lt;/code&gt; is to memoize a function that's defined in the component. If a function is defined in a component, then it will be recreated during each re-render. &lt;code&gt;useCallback(...)&lt;/code&gt; can prevent his. The benefit to stopping the recreation of the function is exemplified best when functions are being passed down as props to child components.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Consider the same &lt;code&gt;&amp;lt;Parent/&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt; components from before with the same &lt;code&gt;React.memo(...)&lt;/code&gt; solution used to prevent re-renders. Except this time &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt; defines a prop for a callback function, and &lt;code&gt;&amp;lt;Parent/&amp;gt;&lt;/code&gt; defines a function called &lt;code&gt;myFunction&lt;/code&gt; and passes it down to &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt;. Also, aside from defining the callback prop, &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt; doesn't even do anything with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Child&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`NON-Callback function called`&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="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-col gap-1 w-1/5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 bg-cyan-600 p-1 border-black rounded-md text-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increment&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Child Rendered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;renderCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;renderCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Render&lt;/span&gt; &lt;span class="na"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, let's see what happens when we change state in the parent component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IPspgbfm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829133757/aa3f67f0-b8e0-43fd-ad1b-5a85e67b2b31.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IPspgbfm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829133757/aa3f67f0-b8e0-43fd-ad1b-5a85e67b2b31.gif" alt="Gif showing the child component re-rendering when the parent component re-renders" width="464" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of &lt;code&gt;React.memo(...)&lt;/code&gt;'s hard work is undone. Although, &lt;code&gt;React.memo(...)&lt;/code&gt; is doing exactly what it's supposed to be doing, but there are two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Each re-render of &lt;code&gt;&amp;lt;Parent/&amp;gt;&lt;/code&gt;, &lt;code&gt;myFunction(...)&lt;/code&gt; gets recreated completely, and occupies a different space in memory, even though nothing has changed about it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;React.memo(...)&lt;/code&gt; is still doing a shallow comparison, but since the old function prop and the new function prop are not referencing the same spot in memory, it thinks that the prop is changed, so &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt; needs to be re-rendered. Remember functions in JavaScript &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions"&gt;are objects&lt;/a&gt; and objects are compared by reference.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;Again, the solution is simple; stop recreating the function and just use the old function by using the &lt;code&gt;useCallback(fn, dependencyList)&lt;/code&gt; hook. The first argument is the function to define whatever work needs to be done, and the second argument, similar to &lt;code&gt;useEffect(...)&lt;/code&gt;, is for a list of state variables that &lt;code&gt;useCallback&lt;/code&gt; will check. As long as none of the state dependencies in the list change, then on every render the same function will be returned instead of creating a new one. Now since the function is the exact same, even from a referential perspective, &lt;code&gt;React.memo(...)&lt;/code&gt;'s shallow comparison will not trigger a re-render of &lt;code&gt;&amp;lt;Child/&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Child&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Callback function called`&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-col gap-1 w-1/5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 bg-cyan-600 p-1 border-black rounded-md text-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increment&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B2KwQNoe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829263314/ec34542e-5203-4c05-8c6a-1307c2717618.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B2KwQNoe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829263314/ec34542e-5203-4c05-8c6a-1307c2717618.gif" alt="Gif showing child component no longer re-rendering when parent component re-renders" width="464" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;useMemo(...)&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Lastly, &lt;code&gt;useMemo(...)&lt;/code&gt; is used to cache the &lt;em&gt;result&lt;/em&gt; of a function. When rendering involves calling some function that produces some value, and the function is doing an expensive calculation but no inputs to the function are changing, then there's no point in the recalculation during each re-render.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Continuing from the last code snippet, let's add a new state variable called &lt;code&gt;myName&lt;/code&gt;, a function called &lt;code&gt;uppercaseName&lt;/code&gt;, and then in the UI let's add a text field and a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag to display the uppercase name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Child&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;myName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMyText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;michael scott&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Callback function called`&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uppercaseName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Processing Name...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;myName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&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="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-col gap-1 w-1/5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 p-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setMyText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 bg-cyan-600 p-1 border-black rounded-md text-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increment&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Hello, this is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;uppercaseName&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oWQQc9xX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829369433/104562b1-584b-461f-a6eb-d185c101d9b5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oWQQc9xX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829369433/104562b1-584b-461f-a6eb-d185c101d9b5.png" alt="Picture showing UI with text field and paragraph added" width="440" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typing something in the text field will display an uppercase version in the paragraph below the button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jBY7YCcE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829449510/e63d1381-91e0-4bea-b80b-7d6c523f6edb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jBY7YCcE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829449510/e63d1381-91e0-4bea-b80b-7d6c523f6edb.gif" alt="Gif showing what happens when typing in the text field" width="444" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, if we open the console and start using the button to increment the count, we can see the function is being ran each time during the re-render even though the name has not changed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yzenxj1N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829533543/0ba6d269-0ec2-470b-b44b-5a9776a5d03c.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yzenxj1N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829533543/0ba6d269-0ec2-470b-b44b-5a9776a5d03c.gif" alt="Gif showing recalculations on every render" width="430" height="964"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;We can use &lt;code&gt;useMemo(...)&lt;/code&gt; to wrap the &lt;code&gt;uppercaseName&lt;/code&gt; function in a similar way we used &lt;code&gt;useCallback(...)&lt;/code&gt;. Except this time the result of &lt;code&gt;useMemo(...)&lt;/code&gt; is a value, and not a function. Like &lt;code&gt;useCallback(...)&lt;/code&gt;, it takes a dependency list, and as long as the state in the dependency list does not change, the result does not have to be recalculated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Child&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;myName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMyText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;michael scott&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Callback function called`&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uppercaseName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Processing Name...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;myName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&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="nx"&gt;myName&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-col gap-1 w-1/5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-3xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&amp;gt; &amp;lt;div&amp;gt;Total: {total}&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 p-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setMyText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt; &amp;lt;button className="border-2 bg-cyan-600 p-1 border-black rounded-md text-white" onClick={&lt;/span&gt;&lt;span class="se"&gt;()&lt;/span&gt;&lt;span class="sr"&gt; =&amp;gt; setTotal&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;total + 1&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;}&amp;gt;Increment Parent Count&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Hello, this is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;uppercaseName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt; &amp;lt;div className="mt-3" /&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt; &amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jzzHg6Ub--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829646663/127c4287-dc8d-4c8b-8b68-2b64eb38e2e8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jzzHg6Ub--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1715829646663/127c4287-dc8d-4c8b-8b68-2b64eb38e2e8.gif" alt="Gif showing the calculation no longer being done needlessly" width="430" height="964"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Over Optimization
&lt;/h2&gt;

&lt;p&gt;After learning about these optimization techniques it may be tempting to start using them everywhere. However that might be overkill for most scenarios. In fact, the React documentation advises to only use these techniques for specific scenarios. However, it is ultimately up to you to decide what is best for your application and when to use what and where to use it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react/memo#should-you-add-memo-everywhere"&gt;Should you add &lt;code&gt;React.memo&lt;/code&gt; everywhere?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react/useCallback#should-you-add-usecallback-everywhere"&gt;Should you add &lt;code&gt;useCallback&lt;/code&gt; everywhere?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react/useMemo#should-you-add-usememo-everywhere"&gt;Should you add &lt;code&gt;useMemo&lt;/code&gt; everywhere?&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;React provides its own mechanisms to developers to optimize their application through memoization.&lt;/p&gt;

&lt;p&gt;Through the use of &lt;code&gt;React.memo(...)&lt;/code&gt; we can limit the number of re-renders of a child component when the parent component re-renders. &lt;code&gt;React.memo(...)&lt;/code&gt; will memoize the child component and only re-render if its props have changed.&lt;/p&gt;

&lt;p&gt;Utilizing &lt;code&gt;useCallback(...)&lt;/code&gt; we can prevent the unnecessary recreation of functions each time a component gets re-rendered. Furthermore, we saw how this can be used in conjunction with &lt;code&gt;React.memo(...)&lt;/code&gt; to limit child component re-renders when passing functions down as props.&lt;/p&gt;

&lt;p&gt;Lastly, &lt;code&gt;useMemo(...)&lt;/code&gt; can be used to avoid duplicate recalculations and data processing, especially if it is an expensive operation. As long as dependent state for the calculation does not change, there is no reason to perform the operation.&lt;/p&gt;




&lt;p&gt;Thank you for taking the time to read my article. I hope it was helpful.&lt;/p&gt;

&lt;p&gt;If you noticed anything in the article that is incorrect or isn't clear, please let me know. I always appreciate the feedback.&lt;/p&gt;

</description>
      <category>react</category>
      <category>memoization</category>
      <category>reacthooks</category>
      <category>optimization</category>
    </item>
    <item>
      <title>Git Reset Modes</title>
      <dc:creator>Nicholas Fragiskatos</dc:creator>
      <pubDate>Wed, 06 Dec 2023 02:58:56 +0000</pubDate>
      <link>https://dev.to/nfragiskatos/git-reset-modes-2c9h</link>
      <guid>https://dev.to/nfragiskatos/git-reset-modes-2c9h</guid>
      <description>&lt;p&gt;Sometimes when working with Git it would be useful to rewind your branch to an earlier commit. Maybe one of your recent commits introduced a bug or you just want to organize your changes differently between commits. Whatever the reason, Git provides this functionality through the &lt;code&gt;git reset&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;In this article I will explain and demonstrate how to use the three most common modes of the &lt;code&gt;git reset&lt;/code&gt; command, &lt;em&gt;soft&lt;/em&gt;, &lt;em&gt;mixed&lt;/em&gt;, and &lt;em&gt;hard&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Background
&lt;/h2&gt;

&lt;p&gt;Before diving into what &lt;code&gt;git reset&lt;/code&gt; is and how it works, we need to have a basic understanding of these four important pieces of Git: &lt;em&gt;working directory&lt;/em&gt;, &lt;em&gt;repository&lt;/em&gt;, &lt;em&gt;index&lt;/em&gt;, and &lt;em&gt;HEAD&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working Directory
&lt;/h3&gt;

&lt;p&gt;The easiest piece to understand is the &lt;em&gt;working directory&lt;/em&gt;, a.k.a. &lt;em&gt;workspace&lt;/em&gt;. This is simply the main directory where all the source files live that you see and edit for your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repository
&lt;/h3&gt;

&lt;p&gt;Typically, when we are working on a project that Git is managing, the working directory houses another directory named &lt;code&gt;.git&lt;/code&gt;. This directory is the &lt;em&gt;repository&lt;/em&gt; and contains all the commit history, branch information, files, etc. for Git to manage the project. The &lt;code&gt;.git&lt;/code&gt; directory is also all that's needed to rebuild (i.e. clone) the repository.&lt;/p&gt;

&lt;p&gt;From Git's perspective the &lt;code&gt;.git&lt;/code&gt; directory is the repository. However, the term &lt;em&gt;repository&lt;/em&gt; is often used more generally to mean the working directory and everything inside it. The important point is that when Git references the &lt;em&gt;repository&lt;/em&gt; it means the &lt;code&gt;.git&lt;/code&gt; directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  HEAD
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;HEAD&lt;/em&gt; is a pointer to the latest commit in the commit history on the current branch reference. Each branch has only one &lt;em&gt;HEAD&lt;/em&gt; that is unique to that specific branch. While often used interchangeably for convenience, branch and &lt;em&gt;HEAD&lt;/em&gt; aren't the same, because a branch represents a collection of commits, while the &lt;em&gt;HEAD&lt;/em&gt; is specifically the latest commit on the branch.&lt;/p&gt;

&lt;p&gt;The repository stores all head references in &lt;code&gt;.git/refs/heads/&lt;/code&gt;. Also, there is a &lt;em&gt;HEAD&lt;/em&gt; file in the root of &lt;code&gt;.git/&lt;/code&gt; that points to a specific head reference in &lt;code&gt;.git/refs/heads&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Index
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;index&lt;/em&gt; is the storage space for all changes that will be included in the next commit and is stored within the repository. The &lt;em&gt;index&lt;/em&gt; might also be referred to as the &lt;em&gt;staging area&lt;/em&gt;, or &lt;em&gt;cache&lt;/em&gt;. When we use the &lt;code&gt;git add&lt;/code&gt; command, the file is then placed in the &lt;em&gt;index&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting the Pieces Together
&lt;/h3&gt;

&lt;p&gt;For visual clarity, below is a simple diagram of how these pieces are related. The working directory encompasses everything, then the repository(&lt;code&gt;.git&lt;/code&gt; directory) contains the index and the HEAD.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OaVt6Buz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829488709/35190bee-1eb6-406e-8641-c001f41cfda3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OaVt6Buz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829488709/35190bee-1eb6-406e-8641-c001f41cfda3.png" alt="Diagram of how the working directory, index, reposiotry, and head are related to each other." width="687" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The File Lifecycle
&lt;/h3&gt;

&lt;p&gt;The example below demonstrates the three main stages for a file when working with Git. It starts in the working directory where It's either a new file or an existing file that has been modified. &lt;sup&gt;1&lt;/sup&gt; Next, when the file is done being modified, it's ready to be added to the index using the &lt;code&gt;git add&lt;/code&gt; command.&lt;sup&gt;2&lt;/sup&gt; Lastly, it is ready to be committed with &lt;code&gt;git commit&lt;/code&gt;. Once committed it becomes part of the latest commit, and this latest commit becomes the new HEAD.&lt;sup&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hlxMj6zr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829562740/70fb1542-983d-4152-b457-18169054df03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hlxMj6zr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829562740/70fb1542-983d-4152-b457-18169054df03.png" alt="Example of the file lifecycle as it transitions from the working directory to the index and finally to the commit history" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's important to know that none of the files are actually getting moved around. Instead, copies of files are being made (it's more complicated than a basic copy and paste, but for modeling purposes copy is accurate enough). All the files in the working directory stay in the working directory. When the file is staged, a copy of it is placed in the index. Then, when the file is committed, another copy is created and added to the repository as a part of the commit history.&lt;/p&gt;

&lt;p&gt;With that being said, it is entirely possible and not uncommon for three different versions of a file to exist at a time between the working directory, index, and HEAD. Take for example, the figure below. Initially, the file is created/edited, staged, and then committed. Meaning all three areas have the same file.&lt;sup&gt;1&lt;/sup&gt; If the file is edited and staged again, but not committed, then the working directory and the index will have a different version of the file than the HEAD.&lt;sup&gt;2&lt;/sup&gt; Finally, if the file is edited again but &lt;em&gt;not&lt;/em&gt; staged, then the working directory now contains a third version of the same file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TT5dRKHF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829618985/47ca74c4-c0f1-4109-b74a-655ab6d5404c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TT5dRKHF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829618985/47ca74c4-c0f1-4109-b74a-655ab6d5404c.png" alt="Example of the same file existing in the working directory, index, and HEAD at the same time" width="800" height="985"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reset Command
&lt;/h2&gt;

&lt;p&gt;A reset command has the following template, where MODE can be &lt;em&gt;soft&lt;/em&gt;, &lt;em&gt;mixed&lt;/em&gt;, or &lt;em&gt;hard&lt;/em&gt;, and the COMMIT_HASH is the hash ID for a commit that can be found when viewing the log.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--MODE&lt;/span&gt; COMMIT_HASH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E.x.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--soft&lt;/span&gt; 78dffe9c5fa346d03458d15862a38325ebb2e896
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At a minimum, a reset is just moving the head back to a previous commit. However, an important thing to consider is what happens to the commits between the new HEAD position and the old HEAD position. Each of those commits contain changes, and what happens to those changes is determined by the different reset modes.&lt;/p&gt;

&lt;p&gt;This is most easily seen through an example. Consider the following branch, &lt;em&gt;my_example_branch&lt;/em&gt;, from the figure below.&lt;sup&gt;1&lt;/sup&gt; If for some reason we don't like commits &lt;em&gt;D&lt;/em&gt; and &lt;em&gt;E&lt;/em&gt; and we want to undo them, we can do a &lt;code&gt;git reset C&lt;/code&gt; to move the head back to commit &lt;em&gt;C&lt;/em&gt;.&lt;sup&gt;2&lt;/sup&gt; This makes commits &lt;em&gt;D&lt;/em&gt; and &lt;em&gt;E&lt;/em&gt; orphaned and no longer part of the branch's commit history.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tMHl-OTJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829762103/b5951cfb-273d-4d70-ba1f-9df0aaedf1c9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tMHl-OTJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829762103/b5951cfb-273d-4d70-ba1f-9df0aaedf1c9.png" alt="Example of how a branch changes after a git reset" width="800" height="767"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Soft Reset
&lt;/h2&gt;

&lt;p&gt;For a soft reset, all current changes in the index remain in the index, all changes in the orphaned commits are placed back in the index, and the working directory is unchanged.&lt;/p&gt;

&lt;p&gt;The example below demonstrates this. We start with a series of five commits: A, B, C, D, and E, all with various changes.&lt;sup&gt;1&lt;/sup&gt; The notation F1A specifies version &lt;em&gt;A&lt;/em&gt; of a file named &lt;em&gt;F1&lt;/em&gt;. It's important to note that in this state we also have changes in the working directory with F3C that haven't been staged, and changes in the index with F2E that haven't been committed.&lt;/p&gt;

&lt;p&gt;Performing a &lt;code&gt;git reset --soft C&lt;/code&gt;&lt;sup&gt;2&lt;/sup&gt; moves the HEAD back to commit C. This causes commits D and E to be orphaned. Commit D has changes F1C and F3B placed back into the index. Notice that F3C and F3B now exist simultaneously in the working directory and index, respectively. Commit E has change F4A placed back into the index. However, change F2D is a little different. Since F2E already exists in the index, and is more recent than F2D, the more recent change is kept.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L3VNu78r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829832388/07e12ebd-c2f7-4033-9735-22c988d3ef92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L3VNu78r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701829832388/07e12ebd-c2f7-4033-9735-22c988d3ef92.png" alt="Example of how a soft reset affects the HEAD, index, and working directory" width="800" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example - Setup Commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;soft_reset       
&lt;span class="nb"&gt;cd &lt;/span&gt;soft_reset
git init
&lt;span class="nb"&gt;touch &lt;/span&gt;F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;touch &lt;/span&gt;F2
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit A"&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;F3
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2 
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit B"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit C"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit D"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2D"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
&lt;span class="nb"&gt;touch &lt;/span&gt;F4
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F4A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F4
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit E"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2E"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add F2
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example - Setup State
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git log &lt;span class="nt"&gt;--name-only&lt;/span&gt;

commit b8ed5b6fb95681eb02a1de265a374ef300ad27b9 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt;
Author: ...
Date: ...

    Commit E

F2
F4

commit e961b6e8eee949fc6f83b89861cafec036686212
Author: ...
Date: ...

    Commit D

F1
F3

commit 78dffe9c5fa346d03458d15862a38325ebb2e896
Author: ...
Date: ...

    Commit C

F1
F2

commit b132b2646c3f6203d27319d6296a1292710f2782
Author: ...
Date: ...

    Commit B

F2
F3

commit 75f789b08f5f7dc11557614fddcb941270829fdc
Author: ...
Date: ...

    Commit A

F1
F2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git status

On branch main
Changes to be committed:
  (use "git restore --staged &amp;lt;file&amp;gt;..." to unstage)
    modified: F2

Changes not staged for commit:
  (use "git add &amp;lt;file&amp;gt;..." to update what will be committed)
  (use "git restore &amp;lt;file&amp;gt;..." to discard changes in working directory)
    modified: F3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example - Soft Reset to Commit C
&lt;/h3&gt;

&lt;p&gt;After running &lt;code&gt;git reset --soft 78dffe9c5fa346d03458d15862a38325ebb2e896&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git status

On branch main
Changes to be committed:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore --staged &amp;lt;file&amp;gt;..."&lt;/span&gt; to unstage&lt;span class="o"&gt;)&lt;/span&gt;
    modified: F1
    modified: F2
    modified: F3
    new file: F4

Changes not staged &lt;span class="k"&gt;for &lt;/span&gt;commit:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to update what will be committed&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore &amp;lt;file&amp;gt;..."&lt;/span&gt; to discard changes &lt;span class="k"&gt;in &lt;/span&gt;working directory&lt;span class="o"&gt;)&lt;/span&gt;
    modified: F3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To show that we have the correct F2E change we can run &lt;code&gt;git diff --cached F2&lt;/code&gt; to get the difference between the index and HEAD versions. It shows the inclusion of the 2 lines from both changes, F2D and F2E.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; F2

diff &lt;span class="nt"&gt;--git&lt;/span&gt; a/F2 b/F2
index a2e06c8..3a24ea5 100644
&lt;span class="nt"&gt;---&lt;/span&gt; a/F2
+++ b/F2
@@ &lt;span class="nt"&gt;-1&lt;/span&gt;,3 +1,5 @@
 F2A
 F2B
 F2C
+F2D
+F2E
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mixed Reset
&lt;/h2&gt;

&lt;p&gt;For a mixed reset, all changes in the orphaned commits are placed back in the working directory and all currently staged changes are unstaged, i.e., moved back into the working directory. This means the index now matches the HEAD.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;br&gt;
The mixed mode is the default mode when performing a reset, and in this case the_mode_flag can be omitted. The following two commands are equivalent:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--mixed&lt;/span&gt; COMMIT_HASH&lt;span class="sb"&gt;`&lt;/span&gt;


git reset COMMIT_HASH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To demonstrate a mixed reset we can use the same setup as before. From the example below, we again start with a series of five commits: A, B, C, D, and E.&lt;sup&gt;1&lt;/sup&gt; Also, as before, in this state we have changes in the working directory with F3C that haven't been staged, and changes in the index with F2E that haven't been committed.&lt;/p&gt;

&lt;p&gt;Performing a &lt;code&gt;git reset --mixed C&lt;/code&gt;&lt;sup&gt;2&lt;/sup&gt; moves the HEAD back to commit C. This causes commits D and E to be orphaned. All changes from the orphaned commits &lt;em&gt;and&lt;/em&gt; any staged changes are placed back into the working directory. Similarly to the previous example, there are overlaps between F2D/F2E, and F3B/F3C resulting in the most recent changes being kept, F2E and F3C. One last thing to note is that F4A is now considered an &lt;em&gt;untracked&lt;/em&gt; file because from the commit history's perspective it's a new file that has never been staged.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1xwMf54x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701830024428/9984a89a-cb7b-4cd9-add9-4da315c254ad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1xwMf54x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701830024428/9984a89a-cb7b-4cd9-add9-4da315c254ad.png" alt="Example of how a mixed reset affects the HEAD, index, and working directory" width="800" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example - Setup Commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;mixed_reset       
&lt;span class="nb"&gt;cd &lt;/span&gt;mixed_reset
git init
&lt;span class="nb"&gt;touch &lt;/span&gt;F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;touch &lt;/span&gt;F2
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit A"&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;F3
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2 
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit B"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit C"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit D"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2D"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
&lt;span class="nb"&gt;touch &lt;/span&gt;F4
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F4A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F4
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit E"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2E"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add F2
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example - Setup State
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git log &lt;span class="nt"&gt;--name-only&lt;/span&gt;

commit fc52174c53e4f3af9f7c85be2f5e15edd51a4e3f &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt;
Author: ...
Date: ...

    Commit E

F2
F4

commit ef5162ee0dc249bc3df73f6330b9bdab20462623
Author: ...
Date: ...

    Commit D

F1
F3

commit efada051fe9b3ac195184008c2dac4a14b501402
Author: ...
Date: ...

    Commit C

F1
F2

commit 4dbd5152f6ee12fc6f8124667513789f3d9466ed
Author: ...
Date: ...

    Commit B

F2
F3

commit 9e3f1ac4b98ab0791183dfa0f06d9a7620706b21
Author: ...
Date: ...

    Commit A

F1
F2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git status

On branch main
Changes to be committed:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore --staged &amp;lt;file&amp;gt;..."&lt;/span&gt; to unstage&lt;span class="o"&gt;)&lt;/span&gt;
    modified: F2

Changes not staged &lt;span class="k"&gt;for &lt;/span&gt;commit:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to update what will be committed&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore &amp;lt;file&amp;gt;..."&lt;/span&gt; to discard changes &lt;span class="k"&gt;in &lt;/span&gt;working directory&lt;span class="o"&gt;)&lt;/span&gt;
    modified: F3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example - Mixed Reset to Commit C
&lt;/h3&gt;

&lt;p&gt;After running &lt;code&gt;git reset --mixed efada051fe9b3ac195184008c2dac4a14b501402&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git status

On branch main
Changes not staged &lt;span class="k"&gt;for &lt;/span&gt;commit:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to update what will be committed&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore &amp;lt;file&amp;gt;..."&lt;/span&gt; to discard changes &lt;span class="k"&gt;in &lt;/span&gt;working directory&lt;span class="o"&gt;)&lt;/span&gt;
    modified: F1
    modified: F2
    modified: F3

Untracked files:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to include &lt;span class="k"&gt;in &lt;/span&gt;what will be committed&lt;span class="o"&gt;)&lt;/span&gt;
    F4

no changes added to commit &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add"&lt;/span&gt; and/or &lt;span class="s2"&gt;"git commit -a"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To show that we have the correct F2E and F3C file versions we can just view their contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;F2

F2A
F2B
F2C
F2D
F2E

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;F3

F3A
F3B
F3C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hard Reset
&lt;/h2&gt;

&lt;p&gt;A hard reset is the simplest but should be used carefully because &lt;em&gt;it is also&lt;/em&gt; &lt;strong&gt;&lt;em&gt;destructive&lt;/em&gt;&lt;/strong&gt;. All changes from the index, working tree, and orphaned commits are deleted.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;br&gt;
While any uncommitted changes in the working directory or index are lost after a hard reset, it is possible to recover changes from orphaned commits using the&lt;a href="https://stackoverflow.com/questions/34751837/git-can-we-recover-deleted-commits"&gt;reflog&lt;/a&gt;. However, that's outside the scope of this article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From the example below, we again start with a series of five commits: A, B, C, D, and E.&lt;sup&gt;1&lt;/sup&gt; Also, as before, in this state we have changes in the working directory with F3C that haven't been staged, and changes in the index with F2E that haven't been committed.&lt;/p&gt;

&lt;p&gt;Performing a &lt;code&gt;git reset --hard C&lt;/code&gt;&lt;sup&gt;2&lt;/sup&gt; moves the HEAD back to commit C. Changes in the index and working directory are discarded, as well as any changes from the orphaned commits, D and E. This leaves the working directory, index, and head all in sync.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7gyQVaGE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701830233585/4e26278f-d9ef-4208-944e-024fc25b99dd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7gyQVaGE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1701830233585/4e26278f-d9ef-4208-944e-024fc25b99dd.png" alt="Example of how a hard reset affects the HEAD, index, and working directory" width="800" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example - Setup Commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;hard_reset       
&lt;span class="nb"&gt;cd &lt;/span&gt;hard_reset
git init
&lt;span class="nb"&gt;touch &lt;/span&gt;F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;touch &lt;/span&gt;F2
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit A"&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;F3
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2 
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit B"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit C"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F1C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3B"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit D"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2D"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
&lt;span class="nb"&gt;touch &lt;/span&gt;F4
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F4A"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F4
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Commit E"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F2E"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F2
git add F2
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"F3C"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; F3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example - Setup State
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git log &lt;span class="nt"&gt;--name-only&lt;/span&gt;

commit b379b56b724c2ad9074d84ea2bae38c3394769a7 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class="o"&gt;)&lt;/span&gt;
Author: ...
Date: ...

    Commit E

F2
F4

commit 82e8bfef9df0e6d53ff6cb21ddf17d4196de340f
Author: ...
Date: ...

    Commit D

F1
F3

commit 967ccf7ce4ec657dcbc9d9985349eda675fb0379
Author: ...
Date: ...

    Commit C

F1
F2

commit f3c30c1d6fc908df990673899264022461914ac6
Author: ...
Date: ...

    Commit B

F2
F3

commit 784afdf9e7d3b7189f457bd5c8cfb6df538eaf15
Author: ...
Date: ...

    Commit A

F1
F2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git status

On branch main
Changes to be committed:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore --staged &amp;lt;file&amp;gt;..."&lt;/span&gt; to unstage&lt;span class="o"&gt;)&lt;/span&gt;
    modified: F2

Changes not staged &lt;span class="k"&gt;for &lt;/span&gt;commit:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to update what will be committed&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore &amp;lt;file&amp;gt;..."&lt;/span&gt; to discard changes &lt;span class="k"&gt;in &lt;/span&gt;working directory&lt;span class="o"&gt;)&lt;/span&gt;
    modified: F3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example - Hard Reset to Commit C
&lt;/h3&gt;

&lt;p&gt;After running &lt;code&gt;git reset --hard 967ccf7ce4ec657dcbc9d9985349eda675fb0379&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git status

On branch main
nothing to commit, working tree clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The &lt;code&gt;git reset&lt;/code&gt; command is a useful feature of Git that allows us to rewind a branch by moving the HEAD to an earlier commit. When rewinding a branch, we can control what happens to changes in the working directory, index, and any orphaned commits by using the three different reset modes: &lt;em&gt;soft&lt;/em&gt;, &lt;em&gt;mixed&lt;/em&gt;, and &lt;em&gt;hard&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;soft&lt;/em&gt; reset will preserve any changes in the index at the time of reset while also placing any changes from orphaned commits back into the index. The working directory is left completely unchanged.&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;mixed&lt;/em&gt; reset preserves all current changes in the working directory. Also, all changes from the index and the orphaned commits are moved back into the working directory. The index is left empty and in sync with the HEAD.&lt;/p&gt;

&lt;p&gt;Lastly, a &lt;em&gt;hard&lt;/em&gt; reset is the simplest because all changes from the working directory, index, and orphaned commits are just deleted.&lt;/p&gt;




&lt;p&gt;Thank you for taking the time to read my article. I hope it was helpful.&lt;/p&gt;

&lt;p&gt;If you noticed anything in the article that is incorrect or isn't clear, please let me know. I always appreciate the feedback.&lt;/p&gt;




</description>
      <category>git</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Saving Simple Data in Android - SharedPreferences and DataStore APIs</title>
      <dc:creator>Nicholas Fragiskatos</dc:creator>
      <pubDate>Fri, 24 Nov 2023 16:22:38 +0000</pubDate>
      <link>https://dev.to/nfragiskatos/saving-simple-data-in-android-4jlp</link>
      <guid>https://dev.to/nfragiskatos/saving-simple-data-in-android-4jlp</guid>
      <description>&lt;p&gt;When it comes to data persistence and storing structured data on an Android device, the first solution that comes to mind might involve using a database, like SQLite, paired with an ORM like Room. However, if the goal is to store some configuration flags, user preferences, settings, or some other relatively small handful of simple data, then reaching for a database might be unnecessary.&lt;/p&gt;

&lt;p&gt;Fortunately, the Android framework provides a few different storage solution APIs just for this use case: &lt;em&gt;SharedPreferences&lt;/em&gt; , &lt;em&gt;Preferences DataStore&lt;/em&gt;, and &lt;em&gt;Proto DataStore&lt;/em&gt;. In this article, we will look at what they are, how they differ, and how to work with them.&lt;/p&gt;

&lt;p&gt;I created an example app to demonstrate the different solutions. I will provide small code snippets where needed, but the full sample project can be found &lt;a href="https://github.com/nfragiskatos/SimpleDataStorageInAndroid" rel="noopener noreferrer"&gt;here on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;The project was created using Android Studio's "&lt;em&gt;Empty Views Activity&lt;/em&gt;" template. Then I created three new Activities, one for each storage implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;SharedPreferencesActivity&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;PrefsDataStoreActivity&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ProtoDataStoreActivity&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each activity contains the same form inputs and a button that when clicked will persist three string values and an integer value. The difference between each activity is which API is used.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1700797043199%2Fac001a5c-cd14-4365-a9fc-b36197c27cab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1700797043199%2Fac001a5c-cd14-4365-a9fc-b36197c27cab.png" alt="View of the three screens in the sample app, each dealing with one of the API storage solutions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Saved Data File Locations
&lt;/h2&gt;

&lt;p&gt;Each API creates its own unique file in app-specific storage to save all the data. Being in app-specific storage means the data will persist until the user either clears the app data, or uninstalls the app.&lt;/p&gt;

&lt;p&gt;Data stored using the SharedPreferences API is located in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/data/data/&amp;lt;APP_NAME&amp;gt;/shared_prefs/&amp;lt;SHARED_PREF_FILE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data stored using the DataStore API (both Preference and Proto) is located in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/data/data/&amp;lt;APP_NAME&amp;gt;/files/datastore/&amp;lt;DATASTORE_FILE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To view these files outside of the app, we can use the &lt;em&gt;Device Explorer&lt;/em&gt; tool in Android Studio.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;View -&amp;gt; Tool Windows -&amp;gt; Device Explorer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  SharedPreferences API
&lt;/h2&gt;

&lt;p&gt;The SharedPreferences API is the original solution, and also the simplest. It stores a collection of key-value pairs where the values are simple data types (String, Float, Int, Long, Boolean) and are stored in an XML file. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/data/data/com.nicholasfragiskatos.preferancestorageexample/shared_prefs/my_prefs.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shared preference file is created using a file name, so any number of preference files can exist at a time for the app as long as a unique name is used. We can have one file for the whole application, one for an Activity, or some combination depending on the business logic and data organization strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating and Retrieving a Shared Preference File
&lt;/h3&gt;

&lt;p&gt;Creating or retrieving a shared preference file requires using &lt;code&gt;Context.getSharedPreferences(String name, int mode)&lt;/code&gt;. Typically this will be through an Activity since an Activity is a Context.&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;SharedPreferencesActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// ....&lt;/span&gt;

    &lt;span class="c1"&gt;// References My_Shared_Prefs.xml&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;mySharedPrefs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getSharedPreferences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"My_Shared_Prefs"&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="nc"&gt;MODE_PRIVATE&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;blockquote&gt;
&lt;p&gt;💡&lt;br&gt;
There are four different modes: MODE_PRIVATE, MODE_WORLD_READABLE, MODE_WORLD_WRITEABLE, and MODE_MULTI_PROCESS. However, since this is an old API, the &lt;em&gt;only mode that is not deprecated&lt;/em&gt; is MODE_PRIVATE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;Activity&lt;/code&gt; class has a wrapper function named &lt;code&gt;getPreferences(int mode)&lt;/code&gt;. Although, all that does is invoke &lt;code&gt;getSharedPreferences(...)&lt;/code&gt; using the class name of the current Activity as the name of the file. 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;SharedPreferencesActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// ....&lt;/span&gt;

    &lt;span class="c1"&gt;// References SharedPreferencesActivity.xml&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;mySharedPrefs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getPreferences&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="nc"&gt;MODE_PRIVATE&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;blockquote&gt;
&lt;p&gt;💡&lt;br&gt;
If the preference file does not already exist, then it will only be created when a value is written. Just calling &lt;code&gt;getSharedPreferences(...)&lt;/code&gt; will not create the file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Writing Data
&lt;/h3&gt;

&lt;p&gt;Writing to the file requires invoking &lt;code&gt;SharedPreferences.edit()&lt;/code&gt; to obtain an &lt;code&gt;Editor&lt;/code&gt; that helps facilitate the file IO. Then, similar to how we work with a &lt;code&gt;Bundle&lt;/code&gt;, we use &lt;code&gt;putInt(...)&lt;/code&gt;, &lt;code&gt;putString(...)&lt;/code&gt;, etc., functions provided by the &lt;code&gt;Editor&lt;/code&gt; to modify the preferences. Each function requires a key and value parameters, where the key is a &lt;code&gt;String&lt;/code&gt;. Lastly, to actually write the changes to disk, we either invoke &lt;code&gt;commit()&lt;/code&gt;, or &lt;code&gt;apply()&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;demographicsPrefs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getSharedPreferences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DEMOGRAPHICS_FILE_KEY&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="nc"&gt;MODE_PRIVATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;demographicsPrefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;edit&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;putString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FIRST_NAME_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="nf"&gt;putString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LAST_NAME_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Knope"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example XML file:&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="cp"&gt;&amp;lt;?xml version='1.0' encoding='utf-8' standalone='yes' ?&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;map&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;string&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"com.nicholasfragiskatos.preferancestorageexample.FIRST_NAME_PREF_KEY"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Leslie&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;string&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"com.nicholasfragiskatos.preferancestorageexample.LAST_NAME_PREF_KEY"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Knope&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;/map&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;apply()&lt;/code&gt; vs &lt;code&gt;commit()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;commit()&lt;/code&gt; writes the data synchronously, and it returns a &lt;code&gt;boolean&lt;/code&gt; on whether or not the new values were successfully written.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;apply()&lt;/code&gt; commits its changes first to the in-memory &lt;code&gt;SharedPreferences&lt;/code&gt; immediately, and also starts an &lt;em&gt;asynchronous&lt;/em&gt; commit to the disk. However, it does not return any value to signal success or failure.&lt;/p&gt;

&lt;p&gt;Unless you need the return value, it's advised to just use &lt;code&gt;apply()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading Data
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;SharedPreferences&lt;/code&gt; provides &lt;code&gt;getInt(...)&lt;/code&gt;, &lt;code&gt;getString(...)&lt;/code&gt;, etc., functions to read data from the preference file. These functions require the same key parameter used to write the value and a default value parameter in case the value doesn't exist.&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;demographicsPrefs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getSharedPreferences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DEMOGRAPHICS_FILE_KEY&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="nc"&gt;MODE_PRIVATE&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;firstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demographicsPrefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FIRST_NAME_PREF_KEY&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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demographicsPrefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LAST_NAME_PREF_KEY&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  DataStore
&lt;/h2&gt;

&lt;p&gt;DataStore is the new API that is meant to replace SharedPreferences. Again, the values are simple data types (String, Float, Int, Long, Boolean). However, unlike SharedPreferences, DataStore uses Kotlin coroutines and Flows to store data asynchronously and guarantee data consistency across multi-process access.&lt;/p&gt;

&lt;p&gt;There are two flavors of DataStore provided to us, &lt;em&gt;Preferences DataStore&lt;/em&gt; and &lt;em&gt;Proto DataStore&lt;/em&gt;. While both are an improvement over regular SharedPreferences, each requires a bit more complexity, with Proto DataStore being the most complex by including Protocol Buffers, as we'll see later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;br&gt;
Creating more than one &lt;code&gt;DataStore&lt;/code&gt; object that references the same file &lt;em&gt;in the same process&lt;/em&gt; will break functionality and result in an &lt;code&gt;IllegalStateException&lt;/code&gt; error when reading/writing data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Viewing DataStore Files
&lt;/h3&gt;

&lt;p&gt;The DataStore implementation used will determine what type of file is created on the device. If the preferences approach is used, then a &lt;code&gt;.preferences_pb&lt;/code&gt; file will be created. If the proto approach is used then a &lt;code&gt;.proto&lt;/code&gt; file will be created. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/data/data/com.nicholasfragiskatos.preferancestorageexample/files/datastore/MyPrefsDataStore.preferences_pb

/data/data/com.nicholasfragiskatos.preferancestorageexample/files/datastore/MyProtoSchema.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, both file types need to be decoded first before they can be viewed outside of the app. Google provides a command line utility called &lt;a href="https://google.github.io/proto-lens/installing-protoc.html" rel="noopener noreferrer"&gt;protoc&lt;/a&gt; for Mac and Linux. &lt;code&gt;protoc&lt;/code&gt; can be used as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--decode_raw&lt;/span&gt; &amp;lt; MyProtoSchema.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Preferences DataStore
&lt;/h3&gt;

&lt;p&gt;To get started with Preference DataStore implementation, we first need to add a dependency to the Gradle file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;implementation &lt;span class="s2"&gt;"androidx.datastore:datastore-preferences:1.0.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to SharedPreferences, we need to create a handle to the file we want to read/write from. This time though it's a &lt;code&gt;DataStore&lt;/code&gt; object that will manage the transactions. To obtain it we use the &lt;code&gt;preferencesDataStore(...)&lt;/code&gt; property delegate on an extension property of &lt;code&gt;Context&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="c1"&gt;// make sure to use androidx.datastore.preferences.core.Preferences&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataStore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Preferences&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;preferencesDataStore&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;"MyPrefsDataStore"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Defining Keys for Values
&lt;/h4&gt;

&lt;p&gt;Like SharedPreferences, we access DataStore preferences with a key, but instead of a simple &lt;code&gt;String&lt;/code&gt; key, we need to create a &lt;code&gt;Preferences.Key&amp;lt;T&amp;gt;&lt;/code&gt; for each value. This allows the key-value pair to be typed. These keys are created using &lt;code&gt;stringPreferencesKey(...)&lt;/code&gt;, &lt;code&gt;intPreferencesKey(...)&lt;/code&gt;, etc.&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;FIRST_NAME_PREF_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stringPreferencesKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${BuildConfig.APPLICATION_ID}.FIRST_NAME_PREF_KEY"&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;LAST_NAME_PREF_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stringPreferencesKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${BuildConfig.APPLICATION_ID}.LAST_NAME_PREF_KEY"&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;FAVORITE_COLOR_PREF_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stringPreferencesKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${BuildConfig.APPLICATION_ID}.FAVORITE_COLOR_PREF_KEY"&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;FAVORITE_ICE_CREAM_PREF_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;intPreferencesKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${BuildConfig.APPLICATION_ID}.FAVORITE_ICE_CREAM_PREF_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Writing Data
&lt;/h4&gt;

&lt;p&gt;Writing to the file requires invoking the &lt;code&gt;DataStore.edit(...)&lt;/code&gt; extension function that takes a suspending lambda function parameter, &lt;code&gt;suspend (MutablePreferences) -&amp;gt; Unit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;MutablePreferences&lt;/code&gt; object implements the index get/set operator functions, so we can read/write values with our defined preference keys using the same syntax as we would for a &lt;code&gt;Map&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;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataStore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Preferences&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;preferencesDataStore&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;"MyPrefsDataStore"&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;PrefsDataStoreActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="k"&gt;private&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;savePreferences&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;firstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ron"&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Swanson"&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;favoriteColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Blue"&lt;/span&gt;  
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;iceCreamId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2131231085&lt;/span&gt; &lt;span class="c1"&gt;// some id for radio button&lt;/span&gt;

        &lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;edit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MutablePreferences&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;  
            &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;FIRST_NAME_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;firstName&lt;/span&gt;  
            &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;LAST_NAME_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;  
            &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;FAVORITE_COLOR_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;favoriteColor&lt;/span&gt;  
            &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;FAVORITE_ICE_CREAM_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iceCreamId&lt;/span&gt;  
        &lt;span class="p"&gt;}&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;&lt;em&gt;MyPrefsDataStore.preferences_pb&lt;/em&gt; content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--decode_raw&lt;/span&gt; &amp;lt; MyPrefsDataStore.preferences_pb

1 &lt;span class="o"&gt;{&lt;/span&gt;
  1: &lt;span class="s2"&gt;"com.nicholasfragiskatos.preferancestorageexample.FIRST_NAME_PREF_KEY"&lt;/span&gt;
  2 &lt;span class="o"&gt;{&lt;/span&gt;
    5: &lt;span class="s2"&gt;"Ron"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
1 &lt;span class="o"&gt;{&lt;/span&gt;
  1: &lt;span class="s2"&gt;"com.nicholasfragiskatos.preferancestorageexample.LAST_NAME_PREF_KEY"&lt;/span&gt;
  2 &lt;span class="o"&gt;{&lt;/span&gt;
    5: &lt;span class="s2"&gt;"Swanson"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
1 &lt;span class="o"&gt;{&lt;/span&gt;
  1: &lt;span class="s2"&gt;"com.nicholasfragiskatos.preferancestorageexample.FAVORITE_COLOR_PREF_KEY"&lt;/span&gt;
  2 &lt;span class="o"&gt;{&lt;/span&gt;
    5: &lt;span class="s2"&gt;"Brown"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
1 &lt;span class="o"&gt;{&lt;/span&gt;
  1: &lt;span class="s2"&gt;"com.nicholasfragiskatos.preferancestorageexample.FAVORITE_ICE_CREAM_PREF_KEY"&lt;/span&gt;
  2 &lt;span class="o"&gt;{&lt;/span&gt;
    3: 2131231085
  &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;h4&gt;
  
  
  Reading Data
&lt;/h4&gt;

&lt;p&gt;Reading from the file is done by collecting on the &lt;code&gt;DataStore.data&lt;/code&gt; property, which is a &lt;code&gt;Flow&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;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataStore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Preferences&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;preferencesDataStore&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;"MyPrefsDataStore"&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;PrefsDataStoreActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&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;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;initFromPreferences&lt;/span&gt;&lt;span class="p"&gt;()&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="n"&gt;dataStore&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="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Preferences&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;firstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;FIRST_NAME_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;  
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;LAST_NAME_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;  
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;favoriteColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;FAVORITE_COLOR_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;  
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;favoriteIceCreamId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;FAVORITE_ICE_CREAM_PREF_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;rbChocolate&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;
  
  
  Proto DataStore
&lt;/h3&gt;

&lt;p&gt;Using the Proto DataStore implementation requires significantly more setup than the previous two methods. However, despite the overhead, this approach does ensure type safety, and read and writes are defined by updating a custom, generated class object with named properties instead of relying on keys.&lt;/p&gt;

&lt;p&gt;To begin, we need the following changes in the Gradle file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add Protobuf plugin&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add Proto DataStore, and ProtoBuf dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a custom Protobuf configuration&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;plugins &lt;span class="o"&gt;{&lt;/span&gt;  
    // ...
    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="s2"&gt;"com.google.protobuf"&lt;/span&gt; version &lt;span class="s2"&gt;"0.9.1"&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;

// ...

dependencies &lt;span class="o"&gt;{&lt;/span&gt;  
    // ...

    implementation &lt;span class="s2"&gt;"androidx.datastore:datastore:1.0.0"&lt;/span&gt;  
    implementation &lt;span class="s2"&gt;"com.google.protobuf:protobuf-javalite:3.25.0"&lt;/span&gt;  

&lt;span class="o"&gt;}&lt;/span&gt;

protobuf &lt;span class="o"&gt;{&lt;/span&gt;  
    protoc &lt;span class="o"&gt;{&lt;/span&gt;  
        artifact &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"com.google.protobuf:protoc:3.21.7"&lt;/span&gt;  
    &lt;span class="o"&gt;}&lt;/span&gt;  

    generateProtoTasks &lt;span class="o"&gt;{&lt;/span&gt;  
        all&lt;span class="o"&gt;()&lt;/span&gt;.each &lt;span class="o"&gt;{&lt;/span&gt; task -&amp;gt;  
            task.builtins &lt;span class="o"&gt;{&lt;/span&gt;  
                java &lt;span class="o"&gt;{&lt;/span&gt;  
                    option &lt;span class="s1"&gt;'lite'&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to create a schema in the &lt;code&gt;app/src/main/proto&lt;/code&gt; directory of the project. It's a simple text file with the extension &lt;code&gt;.proto&lt;/code&gt;. Here's a basic example for the sample application, but the &lt;a href="https://protobuf.dev/overview/" rel="noopener noreferrer"&gt;Protocol Buffer Documentation&lt;/a&gt; provides more details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;proto3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="nx"&gt;option&lt;/span&gt; &lt;span class="nx"&gt;java_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;com.nicholasfragiskatos.preferancestorageexample&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="nx"&gt;option&lt;/span&gt; &lt;span class="nx"&gt;java_multiple_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="nx"&gt;MySettings&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nx"&gt;favorite_color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="nx"&gt;int32&lt;/span&gt; &lt;span class="nx"&gt;favorite_ice_cream_flavor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&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;With the schema defined, a &lt;code&gt;MySettings&lt;/code&gt; class will be generated for us. The generated class implementation is extensive, but one convenient thing to point out is that it has a corresponding property for each property defined in the schema. For example, the schema defines a &lt;code&gt;first_name&lt;/code&gt; property, so &lt;code&gt;MySettings&lt;/code&gt; will have a &lt;code&gt;firstName&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;The next part of the setup is to create a custom &lt;code&gt;Serializer&lt;/code&gt; that tells &lt;code&gt;DataStore&lt;/code&gt; how to read and write our custom data type (&lt;code&gt;MySettings&lt;/code&gt;) as defined by the schema. This is largely boilerplate 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;object&lt;/span&gt; &lt;span class="nc"&gt;MySettingsSerializer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MySettings&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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MySettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MySettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDefaultInstance&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;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;readFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;InputStream&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;MySettings&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;try&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;MySettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="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="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;InvalidProtocolBufferException&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;CorruptionException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cannot read proto."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exception&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;override&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;writeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MySettings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OutputStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&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;Now, when we read from the file &lt;code&gt;DataStore&lt;/code&gt; provides a &lt;code&gt;MySettings&lt;/code&gt; object, and when we write to the file we give &lt;code&gt;DataStore&lt;/code&gt; a &lt;code&gt;MySettings&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Lastly, similar to preferences DataStore, we need to create a &lt;code&gt;DataStore&lt;/code&gt; object that will manage the transactions. This time we use the &lt;code&gt;dataStore(...)&lt;/code&gt; property delegate on an extension property of &lt;code&gt;Context&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;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myProtoDataStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataStore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MySettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyProtoSchema.proto"&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="nc"&gt;MySettingsSerializer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Writing Data
&lt;/h4&gt;

&lt;p&gt;Writing to the file requires invoking the &lt;code&gt;DataStore.updateData(...)&lt;/code&gt; function that takes a suspending lambda function parameter, &lt;code&gt;suspend (MySettings) -&amp;gt; MySettings&lt;/code&gt;. We use the builder pattern to create and return an updated &lt;code&gt;MySettings&lt;/code&gt; object to save.&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;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myProtoDataStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataStore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MySettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyProtoSchema.proto"&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="nc"&gt;MySettingsSerializer&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;ProtoDataStoreActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&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;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&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;ActivityProtoDataStoreBinding&lt;/span&gt;  

    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="k"&gt;private&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;savePreferences&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;firstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Wyatt"&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;favoriteColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Green"&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;iceCreamId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2131231084&lt;/span&gt; &lt;span class="c1"&gt;// some id for radio button&lt;/span&gt;

        &lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myProtoDataStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;  
            &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFirstName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLastName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFavoriteColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;favoriteColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFavoriteIceCreamFlavor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iceCreamId&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="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;MyProtoSchema.proto&lt;/em&gt; content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--decode_raw&lt;/span&gt; &amp;lt; MyProtoSchema.proto
1: &lt;span class="s2"&gt;"Ben"&lt;/span&gt;
2: &lt;span class="s2"&gt;"Wyatt"&lt;/span&gt;
3: &lt;span class="s2"&gt;"Green"&lt;/span&gt;
4: 2131231084
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Reading Data
&lt;/h4&gt;

&lt;p&gt;Like Preferences DataStore, reading from the file is done by collecting on the &lt;code&gt;DataStore.data&lt;/code&gt; property, which is a &lt;code&gt;Flow&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;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myProtoDataStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataStore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MySettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyProtoSchema.proto"&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="nc"&gt;MySettingsSerializer&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;ProtoDataStoreActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&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;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&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;ActivityProtoDataStoreBinding&lt;/span&gt;  

    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="k"&gt;private&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;initFromPreferences&lt;/span&gt;&lt;span class="p"&gt;()&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="n"&gt;myProtoDataStore&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="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;  
            &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;etFirstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firstName&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;etLastName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastName&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;etFavoriteColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;favoriteColor&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;rgIceCreamFlavor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;favoriteIceCreamFlavor&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The Android framework provides the developer with &lt;em&gt;SharedPreferences&lt;/em&gt; , &lt;em&gt;Preferences DataStore&lt;/em&gt;, and &lt;em&gt;Proto DataStore&lt;/em&gt; APIs to persist sets of structured data without having to rely on a database. All three APIs write and read simple values (String, Float, Int, Long, Boolean) to a file in app-specific storage.&lt;/p&gt;

&lt;p&gt;SharedPreferences is the original solution and is built into the &lt;code&gt;Context&lt;/code&gt; interface with the &lt;code&gt;getSharedPreferences(...)&lt;/code&gt; function. We write and read values to an XML file using &lt;code&gt;String&lt;/code&gt; keys. While simple and convenient, it does rely on managing unique keys for all values. Also, it could perform synchronous file I/O on the main UI thread if using &lt;code&gt;commit()&lt;/code&gt;, and even if &lt;code&gt;apply()&lt;/code&gt; is used instead of &lt;code&gt;commit()&lt;/code&gt; then there is no mechanism for signaling success or failure.&lt;/p&gt;

&lt;p&gt;The Preferences DataStore API improves upon SharedPreferences by taking advantage of Kotlin coroutines and Flows to store data asynchronously and guarantee data consistency across multi-processor access. While this solution also relies on keys to write data, this time they are not &lt;code&gt;String&lt;/code&gt; values but instead &lt;code&gt;Preferences.Key&amp;lt;T&amp;gt;&lt;/code&gt; objects that allow the key-value pair to be typed.&lt;/p&gt;

&lt;p&gt;Lastly, we learned about Proto DataStore. Like Preferences DataStore, it provides the benefits of asynchronous writes using coroutines and Flows. Another major benefit is that instead of managing key-value pairs, we get a custom, schema-backed, generated class with regular named properties. Proto DataStore provides this custom object when reading from storage, and we provide the same object when writing back to storage. However, these benefits come at the cost of much greater complexity in setup and configuration.&lt;/p&gt;




&lt;p&gt;Thank you for taking the time to read my article. I hope it was helpful.&lt;/p&gt;

&lt;p&gt;If you noticed anything in the article that is incorrect or isn't clear, please let me know. I always appreciate the feedback.&lt;/p&gt;




</description>
      <category>android</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>androiddevelopment</category>
    </item>
    <item>
      <title>Object Relationships in Room ORM Library for Android</title>
      <dc:creator>Nicholas Fragiskatos</dc:creator>
      <pubDate>Wed, 15 Nov 2023 23:37:24 +0000</pubDate>
      <link>https://dev.to/nfragiskatos/object-relationships-in-room-orm-library-for-android-38kk</link>
      <guid>https://dev.to/nfragiskatos/object-relationships-in-room-orm-library-for-android-38kk</guid>
      <description>&lt;p&gt;Object Relational Mapping (ORM) libraries are common tools for back-end development for interacting with a relational database. As the name implies they help facilitate mapping your data that is stored in a relational database to objects used in your application code. Room is the standard ORM library that sits between your Android application and its SQLite database.&lt;/p&gt;

&lt;p&gt;While not necessary, ORMs provide a lot of functionality out of the box to save the developer time. Using an ORM allows the developer to interact with the database with the same language used in the back end. Instead of having to concern themselves with creating complex SQL queries, interactions with the database can look as simple as a normal function call.&lt;/p&gt;

&lt;p&gt;ORMs typically support object references between entities. Or more specifically, nested entity relationships. For example, consider the following Java code snippet for a Hibernate entity relationship (Hibernate is another popular ORM):&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;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StudentEntity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"STUDENT_ID"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;//....&lt;/span&gt;

    &lt;span class="nd"&gt;@JoinColumn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ADDRESS_ID"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;AddressEntity&lt;/span&gt; &lt;span class="n"&gt;address&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="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddressEntity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ADDRESS_ID"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"STREET_NAME"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;streetName&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;The &lt;code&gt;StudentEntity&lt;/code&gt; object has an &lt;code&gt;AddressEntity&lt;/code&gt; object as a member of its class. This means that when a &lt;code&gt;StudentEntity&lt;/code&gt; is fetched from the database the &lt;code&gt;AddressEntity&lt;/code&gt; object will also be fetched, either eagerly or lazily, and be readily available to access from the &lt;code&gt;StudentEntity&lt;/code&gt; object.&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="n"&gt;someStudent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;streetName&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While Room provides a lot of features, it intentionally does not support this behavior. The focus of this article is to see how we can establish and manage object relationships in Room without relying on nested entities. As we'll see, there are a few different approaches, each valid in its own way depending on the use case.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;br&gt;
In case you are wondering why exactly Room doesn't allow this behavior, there is a section in the &lt;a href="https://developer.android.com/training/data-storage/room/referencing-data#understand-no-object-references"&gt;Android documentation&lt;/a&gt; explaining their reasoning. However, in short, nested models can either be loaded &lt;em&gt;lazily&lt;/em&gt;, meaning they are loaded at the time of access, or &lt;em&gt;eagerly&lt;/em&gt;, meaning all entities are loaded at once. On Android, lazy loading would occur on the UI thread, and even a fast database query could result in the system being unable to meet the 16 ms time limit to calculate and redraw a frame. Eager loading is the other option, but this could result in lots of data being loaded even if the UI doesn't require it, therefore wasting memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I will provide code snippets throughout the article, however, a full sample project can be found &lt;a href="https://github.com/nfragiskatos/ObjectRelationshipsInRoom"&gt;here on my GitHub&lt;/a&gt;. Since the focus of this article is on the database and not the UI, the UI is bare bones, but it provides enough functionality to demonstrate the different approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;@Embedded&lt;/code&gt; Annotation
&lt;/h2&gt;

&lt;p&gt;The easiest approach is to embed the nested object into the entity. This is done by annotating the nested object with &lt;code&gt;@Embedded&lt;/code&gt; which tells Room to create additional columns in the parent entity's table for all the fields in the nested object. Essentially, Room is destructuring the nested object and treating all its fields as if it were part of the parent entity.&lt;/p&gt;

&lt;p&gt;The following shows an example model setup. Notice that the nested address object is a simple data class, not an entity. I did add &lt;code&gt;@ColumnInfo&lt;/code&gt; annotations to the fields in the nested object just for naming clarity, but it does not affect functionality.&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;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentWithEmbedded"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentWithEmbeddedEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoGenerate&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;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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="nd"&gt;@ColumnInfo&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;"first_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;firstName&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="nd"&gt;@ColumnInfo&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;"last_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;lastName&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="nd"&gt;@Embedded&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;AddressForEmbedded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressForEmbedded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@ColumnInfo&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;"house_number_embedded"&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;houseNumber&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="nd"&gt;@ColumnInfo&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;"street_name_embedded"&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;streetName&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="nd"&gt;@ColumnInfo&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;"street_type_embedded"&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;streetType&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="nd"&gt;@ColumnInfo&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;"city_embedded"&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;city&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="nd"&gt;@ColumnInfo&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;"state_embedded"&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;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="nd"&gt;@ColumnInfo&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;"postal_code_embedded"&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;postalCode&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when Room creates the &lt;code&gt;studentWithEmbedded&lt;/code&gt; table in the database, every field in the nested &lt;code&gt;AddressForEmbedded&lt;/code&gt; object will be its own column. Therefore, a full list of columns in the &lt;code&gt;studentWithEmbedded&lt;/code&gt; table will be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;id&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;first_name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;last_name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;house_number_embedded&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;street_name_embedded&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;street_type_embedded&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;city_embedded&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;state_embedded&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;postal_code_embedded&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros and Cons
&lt;/h3&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Probably the simplest of all the approaches&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can handle one-to-one relationships, one student has only one address&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The address data is queryable&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Can not handle a one-to-many, or many-to-many relationship. This means a row in the &lt;code&gt;studentWithEmbedded&lt;/code&gt; table can only have one and only one address association.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If multiple students are associated with the same address, then multiple rows in the &lt;code&gt;studentWithEmbedded&lt;/code&gt; table will have identical values in the associated address columns, i.e., duplicate data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Type Converters
&lt;/h2&gt;

&lt;p&gt;Another approach is to use a Type Converter to serialize the child object to a JSON string, and then store the whole object as a string in one of the table's columns for the parent entity. When the parent entity is fetched from the database the Type Converter will deserialize the string into the correct object.&lt;/p&gt;

&lt;p&gt;The model setup is almost the same as before. The only real differences are the lack of the &lt;code&gt;@Embedded&lt;/code&gt; annotation, and the addition of an &lt;code&gt;id&lt;/code&gt; field in the address object. While an ID is not technically necessary for this to work, this approach can handle one-to-many and many-to-many relationships, so an ID is helpful.&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;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentWithJson"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentWithJsonEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoGenerate&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;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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="nd"&gt;@ColumnInfo&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;"first_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;firstName&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="nd"&gt;@ColumnInfo&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;"last_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;lastName&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="nd"&gt;@ColumnInfo&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;"address_json"&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;AddressForJson&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressForJson&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;houseNumber&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;streetName&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;streetType&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;city&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;state&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;postalCode&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the models set, we can then create a Type Converter to go back and forth between &lt;code&gt;AddressForJson&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt;. For this example, I'm using the Moshi library to handle the JSON conversions.&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;@ProvidedTypeConverter&lt;/span&gt;  
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyRoomTypeConverters&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;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="nd"&gt;@TypeConverter&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;fromAddressJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&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;AddressForJson&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;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;AddressForJson&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;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&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="nd"&gt;@TypeConverter&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;toAddressJson&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="nc"&gt;AddressForJson&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;return&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;AddressForJson&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;toJson&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="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;Room will create the &lt;code&gt;StudentWithJsonEntity&lt;/code&gt; database table with the following columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;id&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;first_name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;last_name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;address_json&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros and Cons
&lt;/h3&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Still relatively simple&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can handle a one-to-one relationship.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can handle a one-to-many relationship, one student can have multiple addresses. In this case, the entity would instead have a field for &lt;code&gt;List&amp;lt;AddressForJson&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The same duplicate data problem as before, if multiple students are associated with the same address, then multiple rows in the &lt;code&gt;studentWithJson&lt;/code&gt; table will have identical values in the &lt;code&gt;address_json&lt;/code&gt; data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From the duplicate data issue in the first point, this approach technically can't handle a many-to-many relationship. While students can have multiple addresses and an address can be used by multiple students, since all addresses are stored in their separate JSON strings, there are no relationships between two identical addresses from different student rows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The address data is not queryable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intermediate Models
&lt;/h2&gt;

&lt;p&gt;The last approach is the most complex, but also the most powerful since it best leverages Room and SQLite. An important distinction between this approach and the previous two is that &lt;em&gt;both objects we are trying to relate are entities with their own respective tables&lt;/em&gt;. We can define relationships between entities by using a few different components together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Room's &lt;code&gt;@Relation&lt;/code&gt; annotation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Room's &lt;code&gt;@ForeignKey&lt;/code&gt; annotation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Room's &lt;code&gt;@Embedded&lt;/code&gt; annotation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Intermediate model&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unlike the previous two approaches where we try and have a nested relationship, this approach avoids that by using a third model called the &lt;em&gt;intermediate model&lt;/em&gt;. The intermediate model contains two fields, one for the parent entity and one for the child entity(s).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@Relation&lt;/code&gt; annotation is used on the child entity in the intermediate model, and it is important because it defines how to relate both tables when &lt;em&gt;retrieving&lt;/em&gt; data.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@ForeignKey&lt;/code&gt; annotation is important because it helps enforce the relational structure when &lt;em&gt;inserting/modifying&lt;/em&gt; data. If you try and insert a row into the child table with a value for the foreign key column that doesn't match any primary key in the parent table an exception will be thrown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed &lt;span class="o"&gt;(&lt;/span&gt;code 787 SQLITE_CONSTRAINT_FOREIGNKEY&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ultimately, the power of this approach is that depending on how we use these components we can model a one-to-one, one-to-many, or many-to-many relationship.&lt;/p&gt;

&lt;h3&gt;
  
  
  One-to-One Relationship
&lt;/h3&gt;

&lt;p&gt;Starting with the simplest relation type, consider again the student and address 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="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentWithOneToOneRelation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToOneRelationEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoGenerate&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;val&lt;/span&gt; &lt;span class="py"&gt;studentId&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;firstName&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;lastName&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="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"addressForOneToOneRelation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressForOneToOneRelationEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  

    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoGenerate&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;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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;houseNumber&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;streetName&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;streetType&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;city&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;state&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="nd"&gt;@ColumnInfo&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;"postal_code"&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;postalCode&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;studentOwnerId&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two things to note:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;StudentWithOneToOneRelationEntity&lt;/code&gt; does not have a nested &lt;code&gt;AddressForOneToOneRelationEntity&lt;/code&gt; field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;AddressForOneToOneRelationEntity&lt;/code&gt; has a reference (&lt;code&gt;studentOwnerId&lt;/code&gt;) that points back to the primary key for &lt;code&gt;StudentWithOneToOneRelationEntity&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With our two entities defined, we now need to create the &lt;em&gt;intermediate object&lt;/em&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;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentWithAddressOneToOneIntermediate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@Embedded&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;student&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToOneRelationEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="nd"&gt;@Relation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
        &lt;span class="n"&gt;parentColumn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="n"&gt;entityColumn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentOwnerId"&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;AddressForOneToOneRelationEntity&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 discussed before, there are only two fields, one for &lt;code&gt;student&lt;/code&gt; and one for &lt;code&gt;address&lt;/code&gt;. The &lt;code&gt;student&lt;/code&gt; field is marked with &lt;code&gt;@Embedded&lt;/code&gt; since it is the parent, and the address field has the &lt;code&gt;@Relation&lt;/code&gt; annotation, since it is the child. The &lt;code&gt;@Relation&lt;/code&gt; annotation needs to be configured with two properties: &lt;code&gt;parentColumn&lt;/code&gt;, which is the name of the primary key column in the parent entity, and &lt;code&gt;entityColumn&lt;/code&gt;, which is the name of the column in the child entity that references the parent entity's primary key.&lt;/p&gt;

&lt;p&gt;With the relationship configured, we can define a query function in the DAO interface for the student.&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;@Dao&lt;/span&gt;  
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToOneRelationDao&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="c1"&gt;// ... &lt;/span&gt;

    &lt;span class="nd"&gt;@Transaction&lt;/span&gt;  
    &lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * from studentWithOneToOneRelation"&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;getAllStudentsWithAddresses&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;StudentWithAddressOneToOneIntermediate&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 function is annotated with &lt;code&gt;@Query&lt;/code&gt; that selects from the student table as we would normally do. However, there are two important differences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The list that is being returned contains intermediate objects (&lt;code&gt;StudentWithAddressOneToOneIntermediate&lt;/code&gt;) instead of the table's entity (&lt;code&gt;StudentWithOneToOneRelationEntity&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The query is marked as a &lt;em&gt;transaction&lt;/em&gt;. This is because Room will query the fields in the intermediate object separately, therefore it needs to make sure that all separate query operations are complete before returning.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Foreign Key Constraint
&lt;/h4&gt;

&lt;p&gt;What we've done so far is enforce a one-to-one relationship between &lt;code&gt;StudentWithOneToOneRelationEntity&lt;/code&gt; and &lt;code&gt;AddressForOneToOneRelationEntity&lt;/code&gt;, but only when &lt;em&gt;retrieving&lt;/em&gt; data. We still need to complete the circle and enforce the one-to-one relationship during the time of &lt;em&gt;insertion/modification&lt;/em&gt;, because right now there are two issues. First, it's still possible to insert a row into the address table where the &lt;code&gt;studentOwnerId&lt;/code&gt; value does not match any &lt;code&gt;studenId&lt;/code&gt; in the student table. Second, it's possible to have two rows in the address table refer to the same student, therefore breaking the one-to-one relationship.&lt;/p&gt;

&lt;p&gt;To fix the first issue, we just need to update the child entity, &lt;code&gt;AddressForOneToOneRelationEntity&lt;/code&gt;, by adding a foreign key.&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;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"addressForOneToOneRelation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="n"&gt;foreignKeys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
        &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
            &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToOneRelationEntity&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;parentColumns&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="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
            &lt;span class="n"&gt;childColumns&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="s"&gt;"studentOwnerId"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;onDelete&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CASCADE&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="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressForOneToOneRelationEntity&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;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;entity&lt;/code&gt; - The name of the parent table.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;parentColumns&lt;/code&gt; - The name of the column in the parent table that the foreign key references.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;childColumns&lt;/code&gt; - The name of the column in the child table that contains the foreign key value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;onDelete&lt;/code&gt; - Defines how to treat the child entity when the parent entity it references is deleted. In the case of &lt;em&gt;cascade&lt;/em&gt;, when the parent entity is deleted the child entity is also deleted.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To fix the second issue we once again update the &lt;code&gt;@Entity&lt;/code&gt; annotation for &lt;code&gt;AddressForOneToOneRelationEntity&lt;/code&gt;. It has an &lt;code&gt;indices&lt;/code&gt; property in which we can add an &lt;code&gt;Index&lt;/code&gt; for the foreign key column, and require it to be unique in the table.&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;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"addressForOneToOneRelation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 

    &lt;span class="n"&gt;foreignKeys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
        &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
            &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToOneRelationEntity&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;parentColumns&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="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
            &lt;span class="n"&gt;childColumns&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="s"&gt;"studentOwnerId"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;onDelete&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CASCADE&lt;/span&gt;       
        &lt;span class="p"&gt;)&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="nc"&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;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"studentOwnerId"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;unique&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="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressForOneToOneRelationEntity&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;Now if we try and insert rows with duplicate &lt;code&gt;studentOwnerId&lt;/code&gt; values an exception will be thrown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Process: com.nicholasfragiskatos.objectrelationshipsinroom, PID: 10239
android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: addressForOneToOneRelation.studentOwnerId &lt;span class="o"&gt;(&lt;/span&gt;code 2067 SQLITE_CONSTRAINT_UNIQUE&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  One-to-Many Relationship
&lt;/h3&gt;

&lt;p&gt;Luckily, the one-to-many relationship is almost identical to the one-to-one relationship except for a couple of minor tweaks.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The child entity no longer needs the unique index.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The intermediate model has a list of addresses instead of just one.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentWithOneToManyRelation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoGenerate&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;val&lt;/span&gt; &lt;span class="py"&gt;studentId&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;firstName&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;lastName&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="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"addressForOneToManyRelation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="n"&gt;foreignKeys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
        &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
            &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToManyRelationEntity&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;parentColumns&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="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
            &lt;span class="n"&gt;childColumns&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="s"&gt;"studentOwnerId"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;onDelete&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CASCADE&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="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressForOneToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  

    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoGenerate&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;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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;houseNumber&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;streetName&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;streetType&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;city&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;state&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="nd"&gt;@ColumnInfo&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;"postal_code"&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;postalCode&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;studentOwnerId&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;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentWithAddressOneToManyIntermediate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@Embedded&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;student&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="nd"&gt;@Relation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;parentColumn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;entityColumn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentOwnerId"&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressForOneToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;?&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@Dao&lt;/span&gt;  
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;StudentWithOneToManyRelationDao&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="c1"&gt;// ... &lt;/span&gt;

    &lt;span class="nd"&gt;@Transaction&lt;/span&gt;  
    &lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * from studentWithOneToManyRelation"&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;getAllStudentsWithAddresses&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;StudentWithAddressOneToManyIntermediate&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;h3&gt;
  
  
  Many-to-Many Relationship
&lt;/h3&gt;

&lt;p&gt;For this approach, the parent entity stays the same again, but the child entity no longer uses a foreign key, which also means it no longer needs the &lt;code&gt;studentOwnerId&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;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentWithManyToManyRelation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentWithManyToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoGenerate&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;val&lt;/span&gt; &lt;span class="py"&gt;studentId&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;firstName&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;lastName&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="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"addressForManyToManyRelation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;AddressForManyToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autoGenerate&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;val&lt;/span&gt; &lt;span class="py"&gt;addressId&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;houseNumber&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;streetName&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;streetType&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;city&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;state&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="nd"&gt;@ColumnInfo&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;"postal_code"&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;postalCode&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 Many-to-Many relationship is slightly more involved, and requires the use of a &lt;em&gt;junction table&lt;/em&gt; (I've also seen this referred to as an &lt;em&gt;Association Table&lt;/em&gt;, or &lt;em&gt;Join Table&lt;/em&gt;), which like any other table, is modeled with an entity class. It's a two-column table where one column holds a reference to the primary key of the parent table and the other column holds a reference to the primary key of the child table. This helps resolve the many-to-many relationship. The primary key for the junction table itself is the composite of both columns.&lt;/p&gt;

&lt;p&gt;For this example, the junction table entity contains two fields, one for the student ID and one for the address ID. Then we make sure to specify &lt;em&gt;both&lt;/em&gt; fields as primary keys in the &lt;code&gt;@Entity&lt;/code&gt; annotation. Since this is a many-to-many relationship there can be multiple rows with duplicate student IDs, and multiple rows with duplicate address IDs, but there can not be multiple rows with a duplicate combination of IDs. It's also probably a good idea to define two foreign keys with cascade deletes, one pointing to the student entity, and one pointing to the address entity. This will avoid having orphaned rows in the table when either a student or address is deleted.&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;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentAddressCrossRef"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="n"&gt;primaryKeys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"addressId"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  

    &lt;span class="n"&gt;foreignKeys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
        &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
            &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StudentWithManyToManyRelationEntity&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;parentColumns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
            &lt;span class="n"&gt;childColumns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
            &lt;span class="n"&gt;onDelete&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CASCADE&lt;/span&gt;  
        &lt;span class="p"&gt;),&lt;/span&gt;  
        &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
            &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AddressForManyToManyRelationEntity&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;parentColumns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"addressId"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
            &lt;span class="n"&gt;childColumns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"addressId"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
            &lt;span class="n"&gt;onDelete&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CASCADE&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="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentAddressCrossRef&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;studentId&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;addressId&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the intermediate object the &lt;code&gt;@Relation&lt;/code&gt; annotation now refers to the &lt;em&gt;junction table&lt;/em&gt;. The &lt;code&gt;parentColumn&lt;/code&gt; property points to the &lt;code&gt;studentId&lt;/code&gt; column in the junction table, and the &lt;code&gt;entityColumn&lt;/code&gt; property points to the &lt;code&gt;addressId&lt;/code&gt; column in the junction table. Lastly, there is the addition of the &lt;code&gt;associateBy&lt;/code&gt; property that specifies the junction table entity 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="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;StudentWithAddressManyToManyIntermediate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@Embedded&lt;/span&gt;  
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;student&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StudentWithManyToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  

    &lt;span class="nd"&gt;@Relation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
        &lt;span class="n"&gt;parentColumn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"studentId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="n"&gt;entityColumn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"addressId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="n"&gt;associateBy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Junction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StudentAddressCrossRef&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="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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressForManyToManyRelationEntity&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;Finally, we define the DAO interface as before.&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;@Dao&lt;/span&gt;  
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;StudentWithManyToManyRelationDao&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="nd"&gt;@Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onConflict&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OnConflictStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE&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;saveStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StudentWithManyToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;  

    &lt;span class="nd"&gt;@Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onConflict&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OnConflictStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE&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;saveAddress&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="nc"&gt;AddressForManyToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;  

    &lt;span class="nd"&gt;@Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onConflict&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OnConflictStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE&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;saveStudentAddressCrossRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StudentAddressCrossRef&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;  

    &lt;span class="nd"&gt;@Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onConflict&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OnConflictStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="nd"&gt;@Transaction&lt;/span&gt;  
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;saveAddress&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="nc"&gt;AddressForManyToManyRelationEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;studentId&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="nf"&gt;saveAddress&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="nf"&gt;saveStudentAddressCrossRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StudentAddressCrossRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;studentId&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;addressId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DELETE FROM studentWithManyToManyRelation where studentId = :studentId"&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;deleteStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;studentId&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;Int&lt;/span&gt;  

    &lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DELETE FROM addressForManyToManyRelation where addressId = :addressId"&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;deleteAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addressId&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;Int&lt;/span&gt;  

    &lt;span class="nd"&gt;@Transaction&lt;/span&gt;  
    &lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * from studentWithManyToManyRelation"&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;getAllStudentsWithAddresses&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;StudentWithAddressManyToManyIntermediate&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;It's important to note that when it comes to inserting new student or address data, &lt;em&gt;if there is a relationship then the junction table needs to be manually updated&lt;/em&gt;. The business logic of when and how a relationship is formed is entirely up to your use case. However, the important point is that just saving a new student or address using the standard &lt;code&gt;@Insert&lt;/code&gt; functions do not automatically create a new entry in the junction table.&lt;/p&gt;

&lt;p&gt;As a simple example, I added the following utility functions to the DAO to facilitate inserting a new address and junction table row within one transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Insert(onConflict = OnConflictStrategy.REPLACE)  
fun saveStudentAddressCrossRef(ref: StudentAddressCrossRef): Long  

@Insert(onConflict = OnConflictStrategy.REPLACE)  
@Transaction  
fun saveAddress(address: AddressForManyToManyRelationEntity, studentId: Long) {  
    saveAddress(address)  
    saveStudentAddressCrossRef(StudentAddressCrossRef(studentId, address.addressId))  
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Room is a powerful and convenient ORM for Android app development, but it does not support nested entity relationships like other ORMs that are used on more traditional back ends. This limitation stems from the need to preserve the responsiveness of the UI and avoid consuming unnecessary memory resources. Despite this limitation, there are still ways to create object relationships.&lt;/p&gt;

&lt;p&gt;First, we looked at embedding the child object into the parent object using Room's &lt;code&gt;@Embedded&lt;/code&gt; annotation. This approach is simple, but it can only support one-to-one relationships, and it does not efficiently handle identical child data being referenced by multiple parent entities.&lt;/p&gt;

&lt;p&gt;Next, we looked at using a Type Converter to serialize the child object to a JSON string to store the whole object as a string in one of the columns for the parent entity. When the parent entity is fetched from the database the Type Converter will deserialize the string into the correct object. This approach can handle one-to-one and one-to-many relationships, but it also requires duplicating data. However, what might be even worse is that the child data is not easily queryable.&lt;/p&gt;

&lt;p&gt;Finally, we learned about the most complex, but powerful approach which best leverages Room and SQLite by treating both parent and child objects as entities, and using a combination of the&lt;code&gt;@Relation&lt;/code&gt; annotation, embedded objects, foreign keys, and intermediate models. This approach allows us to define one-to-one, one-to-many, and many-to-many relationships between objects all while keeping the data queryable without data duplication.&lt;/p&gt;




&lt;p&gt;Thank you for taking the time to read my article. I hope it was helpful.&lt;/p&gt;

&lt;p&gt;If you noticed anything in the article that is incorrect or isn't clear, please let me know. I always appreciate the feedback.&lt;/p&gt;




</description>
      <category>android</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>database</category>
    </item>
    <item>
      <title>Launch Modes in Android - with Examples</title>
      <dc:creator>Nicholas Fragiskatos</dc:creator>
      <pubDate>Tue, 07 Nov 2023 22:30:52 +0000</pubDate>
      <link>https://dev.to/nfragiskatos/launch-modes-in-android-with-examples-3a2j</link>
      <guid>https://dev.to/nfragiskatos/launch-modes-in-android-with-examples-3a2j</guid>
      <description>&lt;p&gt;A &lt;em&gt;Task&lt;/em&gt; is a model that the Android system uses to manage a collection of &lt;em&gt;Activities&lt;/em&gt; that the user is interacting with through some application's workflow. In the simplest, default case we would have a one-to-one mapping between one task and one application's set of Activities. When a user is navigating through a multi-activity application, each new Activity that is launched is added to the associated Task.&lt;/p&gt;

&lt;p&gt;To keep everything organized, a Task places its Activities in a &lt;em&gt;Back Stack&lt;/em&gt;; with each successively opened Activity being added to the top of the stack. This is also what helps facilitate the back navigation when the user presses the back button or swipes back; the current activity gets popped off the stack to be replaced with the Activity underneath it.&lt;/p&gt;

&lt;p&gt;As noted earlier, one Task for one application's set of Activities is the default behavior. However, the Android framework does provide the developer with the power to manipulate this behavior either through the manifest file when declaring the Activity to the system, or by using Intent flags.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In this article, I want to focus on the Android manifest file&lt;/em&gt; and all the different ways in which we can manipulate the Activity-Task association behavior when defining different Activities in the app's manifest.&lt;/p&gt;

&lt;p&gt;I've created a toy app to easily exemplify all the different behaviors. I will provide small code snippets where needed, but the full sample project can be found &lt;a href="https://github.com/nfragiskatos/AndroidLaunchModes"&gt;here on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;I created a brand new project using Android Studio's "&lt;em&gt;Empty Views Activity&lt;/em&gt;" template. Then I created six new Activities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ActivityA&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ActivityB&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ActivityC&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ActivityD&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ActivityE&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ActivityF&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each Activity is basically the same in terms of layout and functionality. Their layout contains a &lt;code&gt;TextView&lt;/code&gt; at the top to easily distinguish between each Activity. Then they also contain six buttons, each to open one of the Activities when clicked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RsDnMHjY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699277958959/1259bac6-9a42-443f-8fe5-059bef0d2992.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RsDnMHjY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699277958959/1259bac6-9a42-443f-8fe5-059bef0d2992.png" alt="Activities A through C" width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lJ_XX-ej--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699277975589/860d21a1-0887-4487-b836-67419ab8e364.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lJ_XX-ej--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699277975589/860d21a1-0887-4487-b836-67419ab8e364.png" alt="Activities D through F" width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, in each Activity, I overrode the &lt;code&gt;onNewIntent(...)&lt;/code&gt; function and displayed a &lt;code&gt;Toast&lt;/code&gt; each time it was called. This function will be important later. An example of what it looks like in &lt;code&gt;ActivityA&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;class&lt;/span&gt; &lt;span class="nc"&gt;ActivityA&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&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;onNewIntent&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;span class="nc"&gt;Intent&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;onNewIntent&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;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&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="s"&gt;"onNewIntent called for Activity A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_LONG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&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;Lastly, instead of just renaming &lt;code&gt;MainActivity&lt;/code&gt;, I updated the &lt;em&gt;AndroidManifest.xml&lt;/em&gt; to make &lt;code&gt;ActivityA&lt;/code&gt; the default launched Activity instead of &lt;code&gt;MainActivity&lt;/code&gt;.&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;manifest&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;  
  ...
&lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;  
 ...
    &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;  
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityA"&lt;/span&gt;  
        &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;  
        &lt;span class="err"&gt;&amp;lt;intent-filter&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;  
            &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  

            &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.LAUNCHER"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  
        &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;  
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MainActivity"&lt;/span&gt;  
        &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;  
    &lt;span class="c"&gt;&amp;lt;!-- &amp;lt;intent-filter&amp;gt;--&amp;gt;&lt;/span&gt;  
    &lt;span class="c"&gt;&amp;lt;!-- &amp;lt;action android:name="android.intent.action.MAIN" /&amp;gt;--&amp;gt;&lt;/span&gt;  

    &lt;span class="c"&gt;&amp;lt;!-- &amp;lt;category android:name="android.intent.category.LAUNCHER" /&amp;gt;--&amp;gt;&lt;/span&gt;  
    &lt;span class="c"&gt;&amp;lt;!-- &amp;lt;/intent-filter&amp;gt;--&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;  

&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Quick Note on a Task's &lt;em&gt;Affinity&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Each Activity, whether explicitly defined or not, has an &lt;em&gt;Affinity&lt;/em&gt;. For a Task, its Affinity would be the Affinity for the Activity at the root of the Task. This holds even if there are multiple Activities with differing Affinities all in one Task (this is possible if all activities are using the &lt;code&gt;standard&lt;/code&gt; Launch Mode that we'll discuss later). For example, say a Task has a Back Stack of the following Activities with Affinities:&lt;/p&gt;

&lt;p&gt;A (&lt;code&gt;.MyAffinity&lt;/code&gt;) -&amp;gt; B (&lt;code&gt;.MyOtherAffinity&lt;/code&gt;) -&amp;gt; C (&lt;code&gt;.YetAnotherAffinity&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Then the Affinity for the task would be &lt;code&gt;.MyAffinity&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An Affinity denotes to Android which Task an Activity prefers to be in. By default, every Activity in an application has the same Affinity. However, there are no hard rules on which Affinity an Activity can have. All Activities in the same application can each have distinct Affinities, and even one Activity from one application can share an Affinity with an Activity from another application.&lt;/p&gt;

&lt;p&gt;An Affinity is only one criterion for the OS to determine which Task to place a new Activity in. As we will see later, the Affinity combines with the &lt;em&gt;Launch Mode&lt;/em&gt; to ultimately determine the placement of the newly opened Activity.&lt;/p&gt;

&lt;p&gt;To set the Affinity of an Activity, you can use the &lt;code&gt;taskAffinity&lt;/code&gt; XML attribute for the &lt;code&gt;&amp;lt;activity&amp;gt;&lt;/code&gt; tag in the &lt;em&gt;AndroidManifest.xml&lt;/em&gt;. If the &lt;code&gt;taskAffinity&lt;/code&gt; attribute is not set, then the default Affinity is the value for the &lt;code&gt;namespace&lt;/code&gt; property in the &lt;em&gt;build.gradle&lt;/em&gt; file.&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;manifest&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;  
  ...
&lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;  
 ...
    &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;  
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityB"&lt;/span&gt;  
        &lt;span class="na"&gt;android:taskAffinity=&lt;/span&gt;&lt;span class="s"&gt;"my.Affinity"&lt;/span&gt;
        &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;   
    &lt;span class="err"&gt;&amp;lt;/activity&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;    
&lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;


// build.gradle
android {   
    ...
    // default Affinity value
    namespace = "com.nicholasfragiskatos.androidlaunchmodes"      
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Valid &lt;code&gt;taskAffinity&lt;/code&gt; Values
&lt;/h3&gt;

&lt;p&gt;The only rule I could find about appropriate values is from this part of the &lt;a href="https://developer.android.com/guide/components/activities/tasks-and-back-stack#Affinities"&gt;documentation&lt;/a&gt; where it says,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;taskAffinity&lt;/code&gt; attribute takes a string value that must be different than the default package name declared in the &lt;code&gt;&amp;lt;manifest&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, I noticed that the value requires a period separator somewhere in the name. Having something like &lt;code&gt;taskAffinity="MyAffinity"&lt;/code&gt; causes a build error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Error running 'app': The application could not be installed: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The following values seem to be OK:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;.myAffinity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;my.Affinity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;myAffinity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;..myAffinity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;. (yes, just a period)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Viewing Tasks on the System
&lt;/h2&gt;

&lt;p&gt;I could not find a good graphical way to view all running Tasks on an emulator in Android Studio. There were some options, but they appeared to be old and incompatible with modern versions of the IDE. The best alternative I could find is using the Android Debugging Bridge (ADB) on the command line and looking through the output of the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adb shell dumpsys activity recents

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give you a list of recent Tasks, and show the list of Activities for the Task, as well as the Affinity, among other information. For example: (output formatted and abbreviated)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks: Recent &lt;span class="c"&gt;#0:{54288a5 #148 type=standard A=10164:.com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;50c032f u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t107&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;eca6d90 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t107&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;a3a3a7 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t107&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;419e7d8 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t107&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;
  
  
  Recent Numbering
&lt;/h3&gt;

&lt;p&gt;The numbering changes based on which Task you viewed most recently. It's best to ignore the number and follow the Task ID (#148 from the example below):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Recent #0:{54288a5 # &lt;strong&gt;148&lt;/strong&gt; type=standard A=10164:.com.nicholasfragiskatos.androidlaunchmodes}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Launch Modes
&lt;/h2&gt;

&lt;p&gt;Launch Modes are a way for the user to specify to the system how a new instance of an Activity should be related to the current Task. We can specify a Launch Mode in either the &lt;em&gt;AndroidManifest.xml&lt;/em&gt; when defining the Activity to the system or in Intent flags when launching the new Activity. There are five different Launch Modes.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;standard&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For this Launch Mode, a new instance of the Activity is created each time regardless of if there already exists an instance of the Activity in the Task. This is the default behavior. You can have as many of the same instances of an Activity across multiple tasks. For instance, all three of these examples are valid states when using the &lt;code&gt;standard&lt;/code&gt; Launch Mode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QYKkEtRC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699280350203/2e4cb82e-ae85-4e52-a293-612ab826dd33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QYKkEtRC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699280350203/2e4cb82e-ae85-4e52-a293-612ab826dd33.png" alt="Examples of valid standard launch mode states" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the example project, to demonstrate this, launch &lt;code&gt;ActivityA&lt;/code&gt; multiple times.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: &lt;/span&gt;

... 

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;449ced3 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t114&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;5d70c45 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t114&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;7a9c8d3 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t114&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;948d5c1 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t114&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;bffb7c9 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t114&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;br&gt;
By default, the new instance of the Activity will be created and placed in the same Task that it was launched from. However, as we will see later, depending on other factors it is not guaranteed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;singleTop&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This Launch Mode is almost identical to &lt;code&gt;standard&lt;/code&gt;. The only difference is that &lt;em&gt;if the Activity you are trying to launch already has an existing instance at the top of the current Task's stack&lt;/em&gt;, then instead of creating a new instance, the system will just call the Activity's &lt;code&gt;onNewIntent(...)&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Considering the example below with the state of the stack being A -&amp;gt; B -&amp;gt; C -&amp;gt; D -&amp;gt; E,&lt;sup&gt;1&lt;/sup&gt; if we try and launch E again no new instance of &lt;code&gt;ActivityE&lt;/code&gt; is created since it's at the top. Instead, the system re-uses the existing instance and just calls &lt;code&gt;onNewIntent(...)&lt;/code&gt;.&lt;sup&gt;2&lt;/sup&gt; However, when we try and launch &lt;code&gt;ActivityC&lt;/code&gt; again, an instance already exists on the stack, but it's not at the top, so a new instance is created and added to the stack.&lt;sup&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BYwXjt2N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390482677/84eb8c53-ed3a-4827-b057-8eb679f45399.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BYwXjt2N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390482677/84eb8c53-ed3a-4827-b057-8eb679f45399.png" alt="example of singleTop launch mode behavior" width="432" height="1464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the example project, to demonstrate this, first, we set the Launch Mode in the manifest for &lt;code&gt;ActivityE&lt;/code&gt;:&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;manifest&amp;gt;&lt;/span&gt;  
    ... 
&lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt;  
    &lt;span class="err"&gt;...&lt;/span&gt;
    &lt;span class="err"&gt;&amp;lt;activity&lt;/span&gt;  
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityE"&lt;/span&gt;  
        &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleTop"&lt;/span&gt;  
        &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  
    ...
    &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;  
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityC"&lt;/span&gt;  
        &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleTop"&lt;/span&gt;  
        &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, remember that we overrode the &lt;code&gt;onNewIntent(...)&lt;/code&gt; function for each Activity to display a Toast:&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;onNewIntent&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;span class="nc"&gt;Intent&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;onNewIntent&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;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&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="s"&gt;"onNewIntent called for Activity E"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_LONG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&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;Starting Activities A -&amp;gt; B -&amp;gt; C -&amp;gt; D -&amp;gt; E -&amp;gt; E will result in the &lt;code&gt;onNewIntent(...)&lt;/code&gt; function being called, but no additional instance of &lt;code&gt;ActivityE&lt;/code&gt; is being added to the stack.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: &lt;/span&gt;

... 

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;f04dc64 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;97af3cc u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;15ff5c9 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;6efecbf u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;5ff0a89 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityE&lt;span class="o"&gt;}&lt;/span&gt; t118&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;However, starting &lt;code&gt;ActivityC&lt;/code&gt; again will result in it being added to the stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: &lt;/span&gt;

... 

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;f04dc64 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;97af3cc u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;15ff5c9 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;6efecbf u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;5ff0a89 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityE&lt;span class="o"&gt;}&lt;/span&gt; t118&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;582171d u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t118&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;
  
  
  &lt;code&gt;singleTask&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;With this Launch Mode, the goal for the system is to maintain a single instance of the Activity at a time. The system will either re-use an existing instance of the Activity, create a new task with the Activity at the root of the stack or use an existing Task that shares the same Affinity. The behavior depends on whether there is already an existing instance of the Activity in &lt;em&gt;some&lt;/em&gt; Task, and then whether there's a Task with the same Affinity.&lt;/p&gt;

&lt;h4&gt;
  
  
  Existing Activity
&lt;/h4&gt;

&lt;p&gt;If the system can find an existing instance of the Activity in either the current Task or another Task then the launched Intent will be routed to the existing Activity to re-use it, and the Activity's &lt;code&gt;onNewIntent(...)&lt;/code&gt; function is invoked, similar to what happens in &lt;code&gt;singleTop&lt;/code&gt;. However, what also happens is that all Activities that are above the re-used Activity will be popped off the stack, leaving the re-used activity back at the top of the stack for the Task.&lt;/p&gt;

&lt;p&gt;In the following example, for the original state, we have Task #1 and Task #2. &lt;code&gt;ActivityD&lt;/code&gt; is set as &lt;code&gt;singleTask&lt;/code&gt; and has &lt;code&gt;.MyAffinity&lt;/code&gt;. All other Activities have the &lt;code&gt;standard&lt;/code&gt; Launch Mode with the default Affinity.&lt;/p&gt;

&lt;p&gt;If we try and start &lt;code&gt;ActivityD&lt;/code&gt; again either in Task #1 or Task #2, then the system will find the existing &lt;code&gt;ActivityD&lt;/code&gt; instance, and route the Intent there. This will result in all other Activities above it being removed from the stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hKtn0Rir--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390618494/4515769a-2a9b-4529-ab19-c43888c48fde.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hKtn0Rir--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390618494/4515769a-2a9b-4529-ab19-c43888c48fde.png" alt="example of singleTask launch mode behavior for existing instance of activity" width="600" height="840"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To demonstrate this in the example project, we update the Launch Mode and Affinity in the manifest for &lt;code&gt;ActivityD&lt;/code&gt;. Set all other Activities back to &lt;code&gt;standard&lt;/code&gt; Launch Mode.&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;activity&lt;/span&gt;  
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityD"&lt;/span&gt;  
    &lt;span class="na"&gt;android:taskAffinity=&lt;/span&gt;&lt;span class="s"&gt;".myAffinity"&lt;/span&gt;  
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleTask"&lt;/span&gt;  
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting Activities A -&amp;gt; B -&amp;gt; C -&amp;gt; D -&amp;gt; E -&amp;gt; A -&amp;gt; B will get us to the original state from the example above where Task #1 has A -&amp;gt; B -&amp;gt; C in its Back Stack, and Task #2 has D -&amp;gt; E -&amp;gt; A -&amp;gt; B in its stack.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks: 

Recent &lt;span class="c"&gt;#0: Task{54288a5 #148 type=standard A=10164:.myAffinity}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:.myAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;e2e12b1 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t148&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;94e9d35 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityE&lt;span class="o"&gt;}&lt;/span&gt; t148&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;c8cccf7 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t148&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;a2fb2ef u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t148&lt;span class="o"&gt;}]&lt;/span&gt;

...

Recent &lt;span class="c"&gt;#1: Task{cb4f549 #147 type=standard A=10164:com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;9d069aa u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t147&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;53edb1a u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t147&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;aa7fbe u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t147&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;If we start &lt;code&gt;ActivityD&lt;/code&gt; again from either Activity the &lt;code&gt;onNewIntent(...)&lt;/code&gt; function will be called for &lt;code&gt;ActivityD&lt;/code&gt; and the Activities above it (E, A, B) will be removed from the stack.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks: Recent &lt;span class="c"&gt;#0: Task{54288a5 #148 type=standard A=10164:.myAffinity ...&lt;/span&gt;

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:.myAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;e2e12b1 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t148&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;h4&gt;
  
  
  Activity Does Not Exist - Shared Affinity
&lt;/h4&gt;

&lt;p&gt;If the Activity does not already exist &lt;em&gt;and&lt;/em&gt; it shares the same Affinity with a Task, then when it is created for the first time it will be placed at the top of the Back Stack of that Task. Every subsequent Activity that is launched will continue to be added to the stack like normal (assuming the other Activities are using the &lt;code&gt;standard&lt;/code&gt; Launch Mode).&lt;/p&gt;

&lt;p&gt;In the diagram below, we start with an original state of A -&amp;gt; B -&amp;gt; C.&lt;sup&gt;1&lt;/sup&gt; &lt;code&gt;ActivityD&lt;/code&gt; has been set as &lt;code&gt;singleTask&lt;/code&gt; with the default Affinity. Since the Affinity matches, launching &lt;code&gt;ActivityD&lt;/code&gt; will result in &lt;code&gt;ActivityD&lt;/code&gt; being placed at the top of the current Task.&lt;sup&gt;2&lt;/sup&gt; We can then add A -&amp;gt; B -&amp;gt; C again.&lt;sup&gt;3&lt;/sup&gt; If we try and launch &lt;code&gt;ActivityD&lt;/code&gt; &lt;em&gt;again&lt;/em&gt;, the OS sees that an instance already exists so it routes the Intent to &lt;code&gt;onNewIntent(...)&lt;/code&gt; and all Activities above &lt;code&gt;ActivityD&lt;/code&gt; are popped off the stack until &lt;code&gt;ActivityD&lt;/code&gt; is at the top.&lt;sup&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2bXft_CB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390735212/bfe6b9c6-5619-440a-8614-f4fbcc64f09b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2bXft_CB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390735212/bfe6b9c6-5619-440a-8614-f4fbcc64f09b.png" alt="example of singleTask launch mode behavior for non existing instance but same affinity" width="442" height="1824"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To demonstrate this in the example project, we update the Launch Mode in the manifest for &lt;code&gt;ActivityD&lt;/code&gt;. Set all other Activities back to &lt;code&gt;standard&lt;/code&gt; Launch Mode.&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;activity&lt;/span&gt;  
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityD"&lt;/span&gt;  
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleTask"&lt;/span&gt;  
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting Activities A -&amp;gt; B -&amp;gt; C will get us to the original state in the diagram.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks: Recent &lt;span class="c"&gt;#0: Task{ed463cf #170 type=standard A=10164:com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;e19f818 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;36def6e u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;96afca3 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t170&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;Starting &lt;code&gt;ActivityD&lt;/code&gt; places the Activity in the current Task.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks: Recent &lt;span class="c"&gt;#0: Task{ed463cf #170 type=standard A=10164:com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;e19f818 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;36def6e u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;96afca3 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;f802a9e u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t170&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;Starting A -&amp;gt; B -&amp;gt; C again from the new Task will create new instances on the stack above &lt;code&gt;ActivityD.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks: Recent &lt;span class="c"&gt;#0: Task{ed463cf #170 type=standard A=10164:com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;e19f818 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;36def6e u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;96afca3 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;f802a9e u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;bacf62a u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;7f315f6 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;356f985 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t170&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;If we start &lt;code&gt;ActivityD&lt;/code&gt; again the &lt;code&gt;onNewIntent(...)&lt;/code&gt; function will be called for &lt;code&gt;ActivityD&lt;/code&gt; and the Activities above it (A, B, C) will be removed from the stack.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks: Recent &lt;span class="c"&gt;#0: Task{ed463cf #170 type=standard A=10164:com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;e19f818 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;36def6e u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;96afca3 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;f802a9e u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t170&lt;span class="o"&gt;}]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Activity Does Not Exist - Different Affinity
&lt;/h4&gt;

&lt;p&gt;If the Activity does not already exist &lt;em&gt;and&lt;/em&gt; it &lt;em&gt;does not&lt;/em&gt; share the same Affinity with an existing Task, then when it is created for the first time it will be placed at the root of a new Task. Every subsequent Activity that is launched in this new Task will continue to be added to the stack like normal (assuming the other Activities are using the &lt;code&gt;standard&lt;/code&gt; Launch Mode).&lt;/p&gt;

&lt;p&gt;In the diagram below, we start with one Task using the default Affinity (Task #1) with an original state of A -&amp;gt; B -&amp;gt; C.&lt;sup&gt;1&lt;/sup&gt; &lt;code&gt;ActivityD&lt;/code&gt; has been set as &lt;code&gt;singleTask&lt;/code&gt; with &lt;code&gt;.MyAffinity&lt;/code&gt;. Since there is no existing instance of &lt;code&gt;ActivityD&lt;/code&gt;, and no Task shares the same Affinity, starting &lt;code&gt;ActivityD&lt;/code&gt; will result in a new Task (Task #2) being created and &lt;code&gt;ActivityD&lt;/code&gt; being placed at the root.&lt;sup&gt;2&lt;/sup&gt;. And of course, from here, we can expect normal behavior. Starting A -&amp;gt; B -&amp;gt; C while in Task #2 will create those Activities and place them on the stack.&lt;sup&gt;3&lt;/sup&gt; If we try and launch &lt;code&gt;ActivityD&lt;/code&gt; &lt;em&gt;again&lt;/em&gt;, the OS sees that an instance already exists so it routes the Intent to &lt;code&gt;onNewIntent(...)&lt;/code&gt; and all Activities above &lt;code&gt;ActivityD&lt;/code&gt; are popped off the stack until &lt;code&gt;ActivityD&lt;/code&gt; is at the top.&lt;sup&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fCM59ofr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390825626/f10f09c9-c258-4939-8fdc-318f6222066b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fCM59ofr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390825626/f10f09c9-c258-4939-8fdc-318f6222066b.png" alt="example of singleTask launch mode behavior for non existing instance and different affinity" width="600" height="1584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To demonstrate this in the example project, we update the Launch Mode and Affinity in the manifest for &lt;code&gt;ActivityD&lt;/code&gt;. Set all other Activities back to &lt;code&gt;standard&lt;/code&gt; Launch Mode.&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;activity&lt;/span&gt;  
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityD"&lt;/span&gt;  
    &lt;span class="na"&gt;android:taskAffinity=&lt;/span&gt;&lt;span class="s"&gt;".MyAffinity"&lt;/span&gt;  
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleTask"&lt;/span&gt;  
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting Activities A -&amp;gt; B -&amp;gt; C will get us to the original state in the diagram.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{1aa5d3a #161 type=standard A=10164:com.nicholasfragiskatos.androidlaunchmodes&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;9fa33e2 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t161&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;1104ae6 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t161&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;a23a934 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t161&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;Starting &lt;code&gt;ActivityD&lt;/code&gt; creates the new Task.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{28ea774 #162 type=standard A=10164:.MyAffinity}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:.MyAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;53ca0ba u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t162&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;Starting A -&amp;gt; B -&amp;gt; C again from the new Task will create new instances on the stack above &lt;code&gt;ActivityD.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{28ea774 #162 type=standard A=10164:.MyAffinity&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:.MyAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;53ca0ba u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t162&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;b15cb2e u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t162&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;31480bf u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t162&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;3de0f78 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t162&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;And finally, starting &lt;code&gt;ActivityD&lt;/code&gt; again will result in &lt;code&gt;onNewIntent(...)&lt;/code&gt; being called and the stack is cleared until &lt;code&gt;ActivityD&lt;/code&gt; is at the top.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{28ea774 #162 type=standard A=10164:.MyAffinity}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:.MyAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;53ca0ba u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t162&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;
  
  
  &lt;code&gt;singleInstance&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This Launch Mode is similar to &lt;code&gt;singleTask&lt;/code&gt; in a few ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The system maintains a single instance of the Activity at a time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating an instance of a &lt;code&gt;singleInstance&lt;/code&gt; Activity will always create a new Task if there is no existing instance already in the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If an existing instance of the &lt;code&gt;singleInstance&lt;/code&gt; Activity already exists, then it is re-used and its &lt;code&gt;onNewIntent(...)&lt;/code&gt; function is invoked.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's no need to go over the similarities again, but there is one important difference; an Activity with &lt;code&gt;singleInstance&lt;/code&gt; &lt;em&gt;will always be the only Activity in a Task&lt;/em&gt;. This means that any other Activity launched by the &lt;code&gt;singleInstance&lt;/code&gt; Activity will always be placed in a different Task.&lt;/p&gt;

&lt;p&gt;In the diagram below, we start with one Task (Task #1) with an original state of A -&amp;gt; B -&amp;gt; C.&lt;sup&gt;1&lt;/sup&gt; &lt;code&gt;ActivityD&lt;/code&gt; has been set as &lt;code&gt;singleInstance&lt;/code&gt;. Since no existing instance of &lt;code&gt;ActivityD&lt;/code&gt; exists starting &lt;code&gt;ActivityD&lt;/code&gt; will result in a new Task (Task #2) being created and &lt;code&gt;ActivityD&lt;/code&gt; being placed at the root.&lt;sup&gt;2&lt;/sup&gt;. Starting E -&amp;gt; F while in Task #2 will create the Activities in Task #1.&lt;sup&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TciStufY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390896820/c59d7769-7f4e-4d5c-847b-61348fdcdfcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TciStufY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699390896820/c59d7769-7f4e-4d5c-847b-61348fdcdfcf.png" alt="example of singleInstnace launch mode" width="600" height="1152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To demonstrate this in the example project, we update the Launch Mode and Affinity in the manifest for &lt;code&gt;ActivityD&lt;/code&gt;. Set all other Activities back to &lt;code&gt;standard&lt;/code&gt; Launch Mode.&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;activity&lt;/span&gt;  
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityD"&lt;/span&gt;  
    &lt;span class="na"&gt;android:taskAffinity=&lt;/span&gt;&lt;span class="s"&gt;".MyAffinity"&lt;/span&gt;  
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleInstance"&lt;/span&gt;  
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting Activities A -&amp;gt; B -&amp;gt; C will get us to the original state in the diagram.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{513838 #184 type=standard A=10164:com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;1722f24 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t184&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;dc1435 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t184&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;2327270 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t184&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;Starting &lt;code&gt;ActivityD&lt;/code&gt; creates the new Task.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{5194c82 #185 type=standard A=10164:.MyAffinity}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:.MyAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;34baff u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD&lt;span class="o"&gt;}&lt;/span&gt; t185&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;Starting E -&amp;gt; F in the new Task will create new instances in the original Task.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{513838 #184 type=standard A=10164:com.nicholasfragiskatos.androidlaunchmodes&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10164:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;1722f24 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA&lt;span class="o"&gt;}&lt;/span&gt; t184&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;dc1435 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB&lt;span class="o"&gt;}&lt;/span&gt; t184&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;2327270 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC&lt;span class="o"&gt;}&lt;/span&gt; t184&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;628a66 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityE&lt;span class="o"&gt;}&lt;/span&gt; t184&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;dfb1fee u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityF&lt;span class="o"&gt;}&lt;/span&gt; t184&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;
  
  
  &lt;code&gt;singleInstancePerTask&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The last Launch Mode is similar to both &lt;code&gt;singleTask&lt;/code&gt; and &lt;code&gt;singleInstance&lt;/code&gt; in a few ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Like &lt;code&gt;singleInstance&lt;/code&gt;, the new Activity will always be created in a new Task if there is no existing instance regardless of Affinity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Like &lt;code&gt;singleTask&lt;/code&gt;, other Activities can exist within the Task.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Like &lt;code&gt;singleTask&lt;/code&gt;, if the &lt;code&gt;singleInstancePerTask&lt;/code&gt; Activity is already a member of a Task, and if we try and launch the Activity again, then all Activities above it in the stack will be removed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both the &lt;code&gt;singleTask&lt;/code&gt; and the &lt;code&gt;singleInstance&lt;/code&gt; Launch Mode shared the singleton property, in which the system will always maintain only a single instance of the Activity at a time across all Tasks. Unlike the latter, it is possible for the &lt;code&gt;singleInstancePerTask&lt;/code&gt; Activity to be started in &lt;em&gt;multiple&lt;/em&gt; Tasks while still maintaining only one instance &lt;em&gt;per&lt;/em&gt; Task. This behavior is possible through the use of the &lt;code&gt;FLAG_ACTIVITY_MULTIPLE_TASK&lt;/code&gt;, or &lt;code&gt;FLAG_ACTIVITY_NEW_DOCUMENT&lt;/code&gt; Intent flags. This article only covers Launch Modes as defined through the manifest, but I thought it important enough to mention.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sharing Affinity
&lt;/h4&gt;

&lt;p&gt;For the &lt;code&gt;singleInstancePerTask&lt;/code&gt; Launch Mode, the Activity will always be created in a new Task if there is no existing instance, regardless of Affinity. This holds even with matching Affinities, but the behavior is a little different.&lt;/p&gt;

&lt;p&gt;Typically, when a new Task has been launched a new window shows up in the app switcher on the device, like the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DbKETGTQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699302594766/6d14bb3b-bb66-48fd-a567-235aa3d03a57.png%3Fheight%3D600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DbKETGTQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699302594766/6d14bb3b-bb66-48fd-a567-235aa3d03a57.png%3Fheight%3D600" alt="example of task switcher showing multiple tasks" width="270" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, if we try and launch a &lt;code&gt;singleInstancePerTask&lt;/code&gt; Activity and there's an existing Task that shares the same Affinity then the system hides the original Task, and we only see one entry in the app switcher.&lt;/p&gt;

&lt;p&gt;In the diagram below we start with one Task (Task #1) with an original state of A -&amp;gt; B.&lt;sup&gt;1&lt;/sup&gt; &lt;code&gt;ActivityE&lt;/code&gt; is started using the &lt;code&gt;singleInstancePerTask&lt;/code&gt; Launch Mode and &lt;code&gt;.MyAffinity&lt;/code&gt; which results in a Task #2 being created.&lt;sup&gt;2&lt;/sup&gt; &lt;code&gt;ActivityF&lt;/code&gt; is started using the &lt;code&gt;singleInstancePerTask&lt;/code&gt; Launch Mode and &lt;code&gt;.MyOtherAffinity&lt;/code&gt; which results in Task #3 being created.&lt;sup&gt;3&lt;/sup&gt; &lt;code&gt;ActivityA&lt;/code&gt; and &lt;code&gt;ActivityB&lt;/code&gt; are started in Task #2 and placed on the top of the stack.&lt;sup&gt;4&lt;/sup&gt; Next, &lt;code&gt;ActivityD&lt;/code&gt; is started using &lt;code&gt;singleInstancePerTask&lt;/code&gt; and &lt;code&gt;.MyAffinity&lt;/code&gt; which results in Task #4 being created. Since Task #2 is also already using &lt;code&gt;.MyAffinity&lt;/code&gt;, Task #2 is hidden.&lt;sup&gt;5&lt;/sup&gt; Lastly, &lt;code&gt;ActivityC&lt;/code&gt; is started using &lt;code&gt;singleInstancePerTask&lt;/code&gt; and the default Affinity which results in Task #5 being created. Since Task #1 is also using the default Affinity, Task #1 is hidden.&lt;sup&gt;6&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H9i8dOg6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699394190694/4f086766-7d58-4781-9233-aaa9c25c92fd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H9i8dOg6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1699394190694/4f086766-7d58-4781-9233-aaa9c25c92fd.png" alt="example of singleinstancepertask behavior when sharing affinity with another task" width="800" height="2168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To replicate this in the example project start by setting &lt;code&gt;ActivityC&lt;/code&gt;, &lt;code&gt;ActivityD&lt;/code&gt;, &lt;code&gt;ActivityE&lt;/code&gt;, and &lt;code&gt;ActivityF&lt;/code&gt; as follows:&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;activity&lt;/span&gt;  
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityF"&lt;/span&gt;  
    &lt;span class="na"&gt;android:taskAffinity=&lt;/span&gt;&lt;span class="s"&gt;".MyOtherAffinity"&lt;/span&gt;  
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleInstancePerTask"&lt;/span&gt;  
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;  
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityE"&lt;/span&gt;  
    &lt;span class="na"&gt;android:taskAffinity=&lt;/span&gt;&lt;span class="s"&gt;".MyAffinity"&lt;/span&gt;  
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleInstancePerTask"&lt;/span&gt;  
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;  
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityD"&lt;/span&gt;  
    &lt;span class="na"&gt;android:taskAffinity=&lt;/span&gt;&lt;span class="s"&gt;".MyAffinity"&lt;/span&gt;  
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleInstancePerTask"&lt;/span&gt;  
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;  
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".launchactivities.ActivityC"&lt;/span&gt;  
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleInstancePerTask"&lt;/span&gt;  
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting Activities A -&amp;gt; B will get us to the original state in the diagram.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{5936bd5 #103 type=standard A=10193:com.nicholasfragiskatos.androidlaunchmodes&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10193:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;68ab88c u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA t103&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;aa8eee0 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB t103&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;Then after launching &lt;code&gt;ActivityE&lt;/code&gt; and &lt;code&gt;ActivityF&lt;/code&gt; we have 3 tasks total.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output: Recent tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Recent &lt;span class="c"&gt;#0: Task{d80e152 #105 type=standard A=10193:.MyOtherAffinity&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10193:.MyOtherAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;f68d1dd u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityF t105&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;span class="o"&gt;]&lt;/span&gt;

Recent &lt;span class="c"&gt;#1: Task{ba9599a #104 type=standard A=10193:.MyAffinity}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10193:.MyAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;7d25e45 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityE t104&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;span class="o"&gt;]&lt;/span&gt;

Recent &lt;span class="c"&gt;#2: Task{5936bd5 #103 type=standard A=10193:com.nicholasfragiskatos.androidlaunchmodes&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10193:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;68ab88c u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityA t103&lt;span class="o"&gt;}&lt;/span&gt;, 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;aa8eee0 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityB t103&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;After launching &lt;code&gt;ActivityD&lt;/code&gt; we see a new Task created, as expected, to house &lt;code&gt;ActivityD&lt;/code&gt;. We also notice that the previous Task with &lt;code&gt;.MyAffinity&lt;/code&gt; (&lt;code&gt;id=104&lt;/code&gt;, has &lt;code&gt;ActivityE&lt;/code&gt;) is no longer in the recent Task list, but it does show up in an extra line above the recent tasks list as part of an &lt;code&gt;mHiddenTasks&lt;/code&gt; output value.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output: Recent tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;mHiddenTasks&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;
Task&lt;span class="o"&gt;{&lt;/span&gt;ba9599a &lt;span class="c"&gt;#104 type=standard A=10193:.MyAffinity}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;

Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{4a12fcd #106 type=standard A=10193:.MyAffinity&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10193:.MyAffinity

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;815b164 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityD t106&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;Likewise, after launching &lt;code&gt;ActivityC&lt;/code&gt;, a new &lt;code&gt;singleInstancePerTask&lt;/code&gt; Activity is created with the default Affinity, and now the previous Task with the default Affinity (&lt;code&gt;id=103&lt;/code&gt;) is added to the hidden Task list.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adb shell dumpsys activity recents&lt;/code&gt; output: Recent tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;mHiddenTasks&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;
Task&lt;span class="o"&gt;{&lt;/span&gt;ba9599a &lt;span class="c"&gt;#104 type=standard A=10193:.MyAffinity}, &lt;/span&gt;
Task&lt;span class="o"&gt;{&lt;/span&gt;5936bd5 &lt;span class="c"&gt;#103 type=standard A=10193:com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;

Recent tasks:

Recent &lt;span class="c"&gt;#0: Task{5ece29 #107 type=standard A=10193:com.nicholasfragiskatos.androidlaunchmodes}&lt;/span&gt;

...

&lt;span class="nv"&gt;affinity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10193:com.nicholasfragiskatos.androidlaunchmodes

...

&lt;span class="nv"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt; 
ActivityRecord&lt;span class="o"&gt;{&lt;/span&gt;2bf9fb0 u0 com.nicholasfragiskatos.androidlaunchmodes/.launchactivities.ActivityC t107&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;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Android framework allows the developer to customize how the system manages the relationships between Activities, Tasks, and its Back Stack.&lt;/p&gt;

&lt;p&gt;The main goal of this article was to review how we can utilize different Launch Modes to manipulate the Task-Activity relationship, but before that, we needed to lay down some groundwork. First we learned about Tasks and Affinities, and how they are related to Activities. Then we learned what an Affinity is and how manipulating an Activity's Affinity can alter how an Activity associates with a particular Task. Lastly, to help facilitate our understanding we utilized ADB to show the current state of Tasks on a device.&lt;/p&gt;

&lt;p&gt;With the groundwork in place, we were able to dive into manipulating an Activity's Launch Mode in its manifest declaration. Each &lt;code&gt;&amp;lt;activity&amp;gt;&lt;/code&gt; tag supports a &lt;code&gt;launchMode&lt;/code&gt; attribute that has five different valid values: &lt;code&gt;standard&lt;/code&gt;, &lt;code&gt;singleTop&lt;/code&gt;, &lt;code&gt;singleTask&lt;/code&gt;, &lt;code&gt;singleInstance&lt;/code&gt;, and &lt;code&gt;singleInstancePerTask&lt;/code&gt;. We studied each Launch Mode in detail and saw how they behave in theory and in a real demo application. While many of the Launch Modes shared behavior with one or more of the other Launch Modes, they all provided their own unique behavior.&lt;/p&gt;




&lt;p&gt;If you noticed anything in the article that is incorrect or isn't clear, please let me know. I always appreciate the feedback.&lt;/p&gt;

</description>
      <category>android</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>androiddevelopment</category>
    </item>
    <item>
      <title>Starting Activities for Results in Android</title>
      <dc:creator>Nicholas Fragiskatos</dc:creator>
      <pubDate>Tue, 24 Oct 2023 20:53:42 +0000</pubDate>
      <link>https://dev.to/nfragiskatos/starting-activities-for-results-in-android-3bcj</link>
      <guid>https://dev.to/nfragiskatos/starting-activities-for-results-in-android-3bcj</guid>
      <description>&lt;p&gt;There are many situations in Android where we need to start a second activity from the current activity or fragment. This second activity could either be another internal activity as defined by your application, or it could be from some external application that we can leverage to do something such as take a picture, choose from a list of contacts, or view something in Google Maps.&lt;/p&gt;

&lt;p&gt;Furthermore, it's very likely that when we want to leverage some other application's functionality we also want that other application to provide us with a result. Luckily, Android provides us with a mechanism for receiving information back from other activities.&lt;/p&gt;

&lt;p&gt;In this article, I want to go over the two different approaches that are available to us to solve this issue: one is the original, but deprecated approach, and the other is the modern approach.&lt;/p&gt;

&lt;p&gt;I will provide small code snippets where needed, but the full sample project can be found &lt;a href="https://github.com/nfragiskatos/ResultsFromActivities"&gt;here on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;br&gt;
Both solutions are available in activities &lt;em&gt;and&lt;/em&gt; fragments. However, for brevity, I'll just be referencing activities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;To start, I created a brand new project using Android Studio's "&lt;em&gt;Empty Views Activity&lt;/em&gt;" template. Then along with the provided &lt;code&gt;MainActivity&lt;/code&gt; I added a &lt;code&gt;SecondActivity&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I added one button to the layout of &lt;code&gt;MainActivity&lt;/code&gt; that when clicked will open &lt;code&gt;SecondActivity&lt;/code&gt;. In the layout of &lt;code&gt;SecondActivity&lt;/code&gt; I have a &lt;code&gt;TextView&lt;/code&gt; to display any input passed from &lt;code&gt;MainActivity&lt;/code&gt;, an &lt;code&gt;EditText&lt;/code&gt; to input a result to send back to &lt;code&gt;MainActivity&lt;/code&gt;, and lastly a &lt;code&gt;Button&lt;/code&gt; that when clicked will finish the activity and return the result.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MainActivity&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iTGWrG25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698091727630/16940b8c-2048-44a9-90a9-1ee226d3a243.png%3Fheight%3D600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iTGWrG25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698091727630/16940b8c-2048-44a9-90a9-1ee226d3a243.png%3Fheight%3D600" alt="Image of the initial layout of MainActivity" width="270" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SecondActivity&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GVYB-6d3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698092418546/aae0ea54-f09c-494f-8cd3-164f82045855.png%3Fheight%3D600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GVYB-6d3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698092418546/aae0ea54-f09c-494f-8cd3-164f82045855.png%3Fheight%3D600" alt="Image of the initial layout of SecondActivity" width="270" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Legacy Approach
&lt;/h2&gt;

&lt;p&gt;The legacy solution is simple enough to implement, and it revolves around two key functions: &lt;code&gt;startActivityForResult(...)&lt;/code&gt;, and &lt;code&gt;onActivityResult(...)&lt;/code&gt;. Both are provided by the activity's parent class.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting &lt;code&gt;SecondActivity&lt;/code&gt; with an Input
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;MainActivity&lt;/code&gt;, I implemented a click listener for the button:&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;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;btnStartSecondActivityOld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nf"&gt;startSecondActivityForResultUsingOldWay&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;startSecondActivityForResultUsingOldWay&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;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&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;SecondActivity&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;putExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
        &lt;span class="nc"&gt;MAIN_ACTIVITY_BUNDLE_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="s"&gt;"Input From Main Activity Old Way"&lt;/span&gt;  
    &lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="nf"&gt;startActivityForResult&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;span class="nc"&gt;MAIN_ACTIVITY_REQUEST_CODE&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;First, I create an &lt;code&gt;Intent&lt;/code&gt; that specifies the current context and the name of the activity's class I wish to start. Also, I used &lt;code&gt;putExtra&lt;/code&gt; to store a &lt;code&gt;String&lt;/code&gt; in the &lt;code&gt;Bundle&lt;/code&gt; of the &lt;code&gt;Intent&lt;/code&gt;, which will be accessible to &lt;code&gt;SecondActivity&lt;/code&gt; as input. Then once I have the &lt;code&gt;Intent&lt;/code&gt; created, all I have to do is call &lt;code&gt;startActivityForResult(...)&lt;/code&gt; passing along the &lt;code&gt;Intent&lt;/code&gt; and a request code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;br&gt;
The request code can be anything. It can be used to keep track of different requests if you expect to be dealing with multiple requests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Handling Input and Returning a Result
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;SecondActivity.onCreate(...)&lt;/code&gt;, I first retrieve the input from the &lt;code&gt;Bundle&lt;/code&gt; of the &lt;code&gt;Intent&lt;/code&gt; and display it. Then I add a click-listener to the button that when fired will return the result. The click listener creates its own &lt;code&gt;Intent&lt;/code&gt; to bundle the return data. Then it calls &lt;code&gt;setResult(...)&lt;/code&gt; to send the &lt;code&gt;Intent&lt;/code&gt; and a result code back to &lt;code&gt;MainActivity&lt;/code&gt;. Lastly, it calls &lt;code&gt;finish()&lt;/code&gt; to end the activity.&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="c1"&gt;// ....&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;inputFromMainActivity&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;span class="nf"&gt;getStringExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MAIN_ACTIVITY_BUNDLE_ID&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;tvInput&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;inputFromMainActivity&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;btnSendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&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;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;etResult&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="nf"&gt;toString&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;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;putExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SECOND_ACTIVITY_BUNDLE_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="nf"&gt;setResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SECOND_ACTIVITY_RESULT_CODE&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;span class="nf"&gt;finish&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;br&gt;
Much like the request code, the result code can also be any integer. For convenience, the &lt;code&gt;Activity&lt;/code&gt; class already has some predefined constants, like &lt;code&gt;Activity.RESULT_OK&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Handling the Result
&lt;/h3&gt;

&lt;p&gt;To process the result back in &lt;code&gt;MainActivity&lt;/code&gt; we override the &lt;code&gt;onActivityResult(...)&lt;/code&gt; function. &lt;code&gt;onActivityResult(...)&lt;/code&gt; has arguments for a request code and a result code so you can uniquely handle each result based on where it came from. It also has an &lt;code&gt;Intent&lt;/code&gt; argument which stores the returned 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="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onActivityResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestCode&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;resultCode&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;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&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;onActivityResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultCode&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestCode&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;MAIN_ACTIVITY_REQUEST_CODE&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;resultCode&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;SecondActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECOND_ACTIVITY_RESULT_CODE&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="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getStringExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecondActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECOND_ACTIVITY_BUNDLE_ID&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="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&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="s"&gt;"Got Result: $it"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_SHORT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&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;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nQolwq7L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698092743770/ffbcb254-2c46-4410-a12f-3d252e6c60bf.gif%3Fheight%3D600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nQolwq7L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698092743770/ffbcb254-2c46-4410-a12f-3d252e6c60bf.gif%3Fheight%3D600" alt="gif showing the workflow of clicking the button to open the second activity, then using the second activity to return a result using the legacy way" width="270" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;p&gt;This seems straightforward enough to implement, so why would this be deprecated?&lt;/p&gt;

&lt;p&gt;One problem is that since the request code is just an integer there is a possibility of duplication between two unrelated requests, or even the wrong integer value being used by mistake which could lead to confusing behavior. A way to circumvent these issues is to define a library of request code constants for each type of request, but that is still not ideal if there are many codes to manage.&lt;/p&gt;

&lt;p&gt;A similar issue is that &lt;code&gt;onActivityResult(...)&lt;/code&gt; is a single function that has to handle &lt;em&gt;all&lt;/em&gt; requests. Depending on the number of requests, this function could just turn into one large, messy switch statement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Activity Result API
&lt;/h2&gt;

&lt;p&gt;The new Activity Result API centers on three new classes: &lt;code&gt;ActivityResultContract&lt;/code&gt;, &lt;code&gt;ActivityResultCallback&lt;/code&gt;, and &lt;code&gt;ActivityResultLauncher&lt;/code&gt;. These three classes are used in the &lt;code&gt;registerForActivityResult(...)&lt;/code&gt; function, which is provided to us by the activity or fragment.&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;@NonNull&lt;/span&gt;   
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;O&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ActivityResultLauncher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;registerForActivityResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;  
    &lt;span class="nd"&gt;@NonNull&lt;/span&gt; &lt;span class="nc"&gt;ActivityResultContract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;I&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;O&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;contract&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  
    &lt;span class="nd"&gt;@NonNull&lt;/span&gt; &lt;span class="nc"&gt;ActivityResultCallback&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;O&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the name implies, &lt;code&gt;registerForActivityResult(...)&lt;/code&gt; will register your callback, but it &lt;em&gt;will not&lt;/em&gt; launch anything. That is the responsibility of the &lt;code&gt;ActivityResultLauncher&lt;/code&gt; object that &lt;code&gt;registerForActivityResult(...)&lt;/code&gt; returns. We can use the &lt;code&gt;ActivityResultLauncher&lt;/code&gt; wherever in our code we are ready to launch the request.&lt;/p&gt;

&lt;p&gt;The first argument we need to pass &lt;code&gt;registerForActivityResult(...)&lt;/code&gt; is an instance of an &lt;code&gt;ActivityResultContract&lt;/code&gt;. This contract is essentially a way to define the input and output for the request in a type-safe way. We'll look more into the details of contracts in a later section when we implement our own. Luckily, there's an existing &lt;code&gt;ActivityResultContracts&lt;/code&gt; class (notice the additional 's' on the end) that contains several prebuilt contracts to use.&lt;/p&gt;

&lt;p&gt;Finally, the last piece is the &lt;code&gt;ActivityResultCallback&lt;/code&gt; argument. This is what is called when the result is ready to be returned. The callback is given the type of result as defined by the output of the contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;First, I defined a top-level &lt;code&gt;ActivityResultLauncher&lt;/code&gt; property for the &lt;code&gt;MainActivity&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;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;startSecondActivityForResultLauncher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ActivityResultLauncher&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Intent&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;registerForActivityResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ActivityResultContracts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StartActivityForResult&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;activityResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ActivityResult&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;activityResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resultCode&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;SecondActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECOND_ACTIVITY_RESULT_CODE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;activityResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getStringExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecondActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECOND_ACTIVITY_BUNDLE_ID&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="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&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="s"&gt;"Got Result: $it"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_SHORT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&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;For the contract, I am passing the prebuilt &lt;code&gt;StartActivityForResult&lt;/code&gt; contract, which defines an &lt;code&gt;Intent&lt;/code&gt; as an input and an &lt;code&gt;ActivityResult&lt;/code&gt; as the output.&lt;/p&gt;

&lt;p&gt;Therefore, in the callback function, I can take the &lt;code&gt;ActivityResult&lt;/code&gt;, do some code comparisons and then grab the data from the bundle just like in &lt;code&gt;onActivityResult(...)&lt;/code&gt; from the legacy approach.&lt;/p&gt;

&lt;p&gt;For the UI I add another button to my view and then define an on-click to launch the request:&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;Button&lt;/span&gt;  
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/btnStartSecondActivityNew"&lt;/span&gt;  
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&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;"Start SecondActivity (new)"&lt;/span&gt;  
    &lt;span class="na"&gt;app:layout_constraintEnd_toEndOf=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;  
    &lt;span class="na"&gt;app:layout_constraintStart_toStartOf=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;  
    &lt;span class="na"&gt;app:layout_constraintTop_toBottomOf=&lt;/span&gt;&lt;span class="s"&gt;"@+id/btnStartSecondActivityOld"&lt;/span&gt; 
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;btnStartSecondActivityNew&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nf"&gt;startSecondActivityUsingNewApi&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;startSecondActivityUsingNewApi&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;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&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;SecondActivity&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;putExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
        &lt;span class="nc"&gt;MAIN_ACTIVITY_BUNDLE_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="s"&gt;"Input From Main Activity New API"&lt;/span&gt;  
    &lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;startSecondActivityForResultLauncher&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;intent&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;StartActivityForResult&lt;/code&gt; contract takes an &lt;code&gt;Intent&lt;/code&gt; as an input, I create one in the same way that I did when calling &lt;code&gt;startActivityForResult(...)&lt;/code&gt; for the legacy approach. The &lt;code&gt;Intent&lt;/code&gt; defines the context, the activity class to start, as well as some input &lt;code&gt;String&lt;/code&gt; value. Then it's as simple as calling the &lt;code&gt;launch(...)&lt;/code&gt; function on our &lt;code&gt;ActivityResultLauncher&lt;/code&gt; object and passing in the &lt;code&gt;Intent&lt;/code&gt; as input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dNva-4MB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698093022368/ce6a2fa3-18da-41bb-a0f8-31a018f3109f.gif%3Fheight%3D600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dNva-4MB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698093022368/ce6a2fa3-18da-41bb-a0f8-31a018f3109f.gif%3Fheight%3D600" alt="gif showing the workflow of clicking the button to open the second activity, then using the second activity to return a result using the new Activity Result API" width="270" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;p&gt;This approach provides us with a few very nice benefits over the deprecated approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We no longer have to worry about request code handling and maintenance. Each separate request that's launched has its own callback. We are no longer limited to one callback function (&lt;code&gt;onActivityResult(...)&lt;/code&gt;) handling &lt;em&gt;all&lt;/em&gt; requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Because we are using the &lt;code&gt;ActivityResultContract&lt;/code&gt; class, we get the convenience of a strongly typed input and output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ActivityResultContract&lt;/code&gt; also wraps up some of the boilerplate code for managing the input and output of the request. We will see in the next section that if we create our own custom contract we can move even more input and output logic into the contract.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Activity Result API with a Custom Contract
&lt;/h2&gt;

&lt;p&gt;Creating our own custom contract involves implementing two functions from &lt;code&gt;ActivityResultContract&lt;/code&gt;: one to define how our input is processed and one to define how the output is processed.&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;ActivityResultContract&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;I&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;O&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;abstract&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createIntent&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="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;I&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Intent&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;parseResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultCode&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;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;O&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice that for the implementation, all we are doing is moving some code from the activity into these functions. In &lt;code&gt;createIntent(...)&lt;/code&gt; I'm creating the same intent as before. Then in &lt;code&gt;parseResult(...)&lt;/code&gt; I'm doing the same result code checks and getting the result from the &lt;code&gt;Bundle&lt;/code&gt; as before.&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;MyCustomContract&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ActivityResultContract&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;,&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="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createIntent&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="n"&gt;input&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;Intent&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;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&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;SecondActivity&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;putExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
            &lt;span class="nc"&gt;MAIN_ACTIVITY_BUNDLE_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="n"&gt;input&lt;/span&gt;  
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;intent&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;parseResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultCode&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;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&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;resultCode&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;SecondActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECOND_ACTIVITY_RESULT_CODE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getStringExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecondActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECOND_ACTIVITY_BUNDLE_ID&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="k"&gt;return&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;return&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;Now that I have my custom contract I can go ahead and define another top level &lt;code&gt;ActivityResultLauncher&lt;/code&gt; property for the &lt;code&gt;MainActivity&lt;/code&gt; class. Notice that now I don't have to handle any result code checking in the callback since I handle all of that in &lt;code&gt;MyCustomContract.parseResult(...)&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="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;startSecondActivityCustomContractLauncher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nf"&gt;registerForActivityResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyCustomContract&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;:&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;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;result&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="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&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="s"&gt;"Got Result: $it"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_SHORT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&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 again updated the UI with another button and click listener. Similarly to the simplified callback definition, the launch call is also simplified since all I have to do is pass the input and &lt;code&gt;MyCustomContract.createIntent(...)&lt;/code&gt; handles any &lt;code&gt;Intent&lt;/code&gt; building logic.&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;Button&lt;/span&gt;  
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/btnStartSecondActivityCustomContract"&lt;/span&gt;  
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&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;"Start SecondActivity (Custom Contract)"&lt;/span&gt;  
    &lt;span class="na"&gt;app:layout_constraintEnd_toEndOf=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;  
    &lt;span class="na"&gt;app:layout_constraintStart_toStartOf=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;  
    &lt;span class="na"&gt;app:layout_constraintTop_toBottomOf=&lt;/span&gt;&lt;span class="s"&gt;"@+id/btnStartSecondActivityNew"&lt;/span&gt; 
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;btnStartSecondActivityCustomContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;startSecondActivityCustomContractLauncher&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="s"&gt;"Custom Contract Input"&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://res.cloudinary.com/practicaldev/image/fetch/s--lbHg5xPj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698178001479/37962912-4655-40b5-a2b2-6cc6585fa6be.gif%3Fheight%3D600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lbHg5xPj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1698178001479/37962912-4655-40b5-a2b2-6cc6585fa6be.gif%3Fheight%3D600" alt="gif showing the workflow of clicking the button to open the second activity, then using the second activity to return a result using the Activity Result API with a custom contract" width="270" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The Activity Result API provides us with a safer and more convenient way of launching activities that are expected to return some result.&lt;/p&gt;

&lt;p&gt;We first looked at the old approach and its straightforward implementation. However, although it works well for simple cases, it can get messy for complex cases where we need to handle many different requests. Managing request code uniqueness, and having one large callback function to handle &lt;em&gt;all&lt;/em&gt; requests is less than ideal from a maintainability standpoint.&lt;/p&gt;

&lt;p&gt;We then explored how to utilize &lt;code&gt;ActivityResultContract&lt;/code&gt;, &lt;code&gt;ActivityResultCallback&lt;/code&gt;, &lt;code&gt;ActivityResultLauncher&lt;/code&gt;, and &lt;code&gt;registerForActivityResult(...)&lt;/code&gt; from the Activity Result API. This implementation removed the need for request code handling, brought us type safety, and cleaned up the code by allowing for individual callbacks for each request type.&lt;/p&gt;

&lt;p&gt;Lastly, we looked at how to create our own &lt;code&gt;ActivityResultContract&lt;/code&gt; implementation. By rolling our own, we were able to further clean up the code in the activity by moving the intent creation and much of the result handling into the contract.&lt;/p&gt;




&lt;p&gt;If you noticed anything in the article that is incorrect or isn't clear, please let me know. I always appreciate the feedback.&lt;/p&gt;

</description>
      <category>android</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>androiddevelopment</category>
    </item>
    <item>
      <title>Function Types with Receivers in Kotlin - The Power Behind Kotlin's apply, with, and run Scope Functions</title>
      <dc:creator>Nicholas Fragiskatos</dc:creator>
      <pubDate>Wed, 18 Oct 2023 04:12:30 +0000</pubDate>
      <link>https://dev.to/nfragiskatos/function-types-with-receivers-the-power-behind-kotlins-apply-with-and-run-scope-functions-32ie</link>
      <guid>https://dev.to/nfragiskatos/function-types-with-receivers-the-power-behind-kotlins-apply-with-and-run-scope-functions-32ie</guid>
      <description>&lt;p&gt;When we invoke one of Kotlin's &lt;em&gt;Scope&lt;/em&gt; functions (&lt;code&gt;apply&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;let&lt;/code&gt;, &lt;code&gt;also&lt;/code&gt;, or &lt;code&gt;with&lt;/code&gt;) a temporary scope/context is created for the object, and you can access the object without its name. Depending on the function you can reference the context object using either &lt;code&gt;it&lt;/code&gt;, or implicitly with &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;apply&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, and &lt;code&gt;with&lt;/code&gt; functions provide the context object with &lt;code&gt;this&lt;/code&gt;, and most interestingly, as a result, they let you define your function block as if it were a native member of the object's type.&lt;/p&gt;

&lt;p&gt;For example, consider the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;myList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ann"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

&lt;span class="n"&gt;myList&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;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Chris"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ron"&lt;/span&gt;&lt;span class="p"&gt;)&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;"[${myList.joinToString("&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="c1"&gt;// Output: ["Leslie", "Ben", "Ann", "Chris"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;add&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; are both functions as defined by the &lt;code&gt;MutableList&lt;/code&gt; interface, but because of the lambda's implicit &lt;code&gt;this&lt;/code&gt; context, we can reference them without any qualifiers. Unlike if using &lt;code&gt;let&lt;/code&gt;, for example. However, even with &lt;code&gt;let&lt;/code&gt;, we can achieve the same outcome:&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;myList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ann"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="n"&gt;myList&lt;/span&gt;&lt;span class="p"&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;it&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="s"&gt;"Chris"&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;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ron"&lt;/span&gt;&lt;span class="p"&gt;)&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;"[${myList.joinToString("&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="c1"&gt;// Output: ["Leslie", "Ben", "Ann", "Chris"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can take a look at the definition of the &lt;code&gt;apply&lt;/code&gt; function and see it's very short. The real functionality that we are interested in lies in the function's argument, and the last two lines.&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="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InlineOnly&lt;/span&gt;  
&lt;span class="k"&gt;public&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;T&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="n"&gt;block&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="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nf"&gt;contract&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nf"&gt;callsInPlace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InvocationKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EXACTLY_ONCE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="nf"&gt;block&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We can disregard the&lt;code&gt;contract{}&lt;/code&gt;block. That's a Kotlin feature that allows the developer to share some extra metadata with the compiler.&lt;a href="https://blog.kotlin-academy.com/understanding-kotlin-contracts-f255ded41ef2?gi=922710c454a4"&gt;Here is a good blog post about it.&lt;/a&gt; For this discussion about Function Types with Receivers, it's not necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From just naively using the &lt;code&gt;apply&lt;/code&gt; function, we know that it runs some block of code that we pass to it and that block of code is within the &lt;code&gt;this&lt;/code&gt; context, and lastly the &lt;code&gt;apply&lt;/code&gt; function returns the context object itself as a result.&lt;/p&gt;

&lt;p&gt;That's exactly what we see happening in the last two lines of the function. There's an invocation of &lt;code&gt;block&lt;/code&gt;, which is the functional parameter passed by the caller, and then finally it just returns &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, &lt;code&gt;block&lt;/code&gt; doesn't seem to be a regular functional parameter. We notice that its type is a little different. It looks more like an &lt;a href="https://kotlinlang.org/docs/extensions.html#extension-functions"&gt;Extension Function&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="n"&gt;block&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parameter is similar but not quite an extension function. It is instead a Function Type with a Receiver. Let's dive deeper into what that means by first starting with breaking this feature down into its two key parts, function types and receivers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function Types
&lt;/h2&gt;

&lt;p&gt;Just like variables, functions in Kotlin can also have a type. A function type uses special notation that defines the function's arguments and return type. Function types have the following general template:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(A, B, C,...) -&amp;gt; Z&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a type that represents a function with arguments of types A, B, C, etc. and returns a value of type Z.&lt;/p&gt;

&lt;p&gt;Some concrete examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;() -&amp;gt; Unit&lt;/code&gt;, a function that takes no arguments, and returns nothing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(String) -&amp;gt; Int&lt;/code&gt;, a function that takes a &lt;code&gt;String&lt;/code&gt; argument and returns an &lt;code&gt;Int&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;((Char) -&amp;gt; Unit) -&amp;gt; Unit&lt;/code&gt;, a higher-order function that takes a function as an argument and returns nothing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kotlin, like many other programming languages, treats functions as first-class citizens. This means you can use a function in the same ways you would use any other type: assigning functions to variables, passing them as arguments to other functions (higher-order functions), and even returning a function as a result of another function.&lt;/p&gt;

&lt;p&gt;Kotlin provides us with a good bit of freedom with how we can define an implementation of a function type. No matter which way it is defined it can still be used in a higher-order function and it will provide the same results.&lt;/p&gt;

&lt;p&gt;As an example, let's take a look at the &lt;code&gt;filter&lt;/code&gt; function that we have access to when working with a &lt;code&gt;Collection&lt;/code&gt;. When we call &lt;code&gt;filter&lt;/code&gt; all we must do is make sure to provide it with a function type that accepts an argument of type T and returns a boolean.&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;public&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="nf"&gt;Iterable&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;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predicate&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;Boolean&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;filterTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ArrayList&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;predicate&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 are the different ways we can satisfy this functional argument when invoking &lt;code&gt;filter&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Functions
&lt;/h3&gt;

&lt;p&gt;Lambda functions allow the developer to quickly and conveniently define an implementation for a functional argument when invoking a higher-order function without first having to define it elsewhere. This is probably the most common way of invoking functions with a functional 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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;myList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Anne"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chris"&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;filterByLambda&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myList&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;str&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="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNotBlank&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&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;"filterByLambda: [${filterByLambda.joinToString("&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="c1"&gt;// Output: &lt;/span&gt;
&lt;span class="c1"&gt;// filterByLambda: ["Leslie", "Chris"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Anonymous Functions
&lt;/h3&gt;

&lt;p&gt;Anonymous functions are similar to lambda functions but with different 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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;myList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Anne"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chris"&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;filterByAnonymous&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myList&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="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNotBlank&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&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;"filterByAnonymous: [${filterByAnonymous.joinToString("&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="c1"&gt;// Output: &lt;/span&gt;
&lt;span class="c1"&gt;// filterByAnonymous: ["Leslie", "Chris"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Function Variables
&lt;/h3&gt;

&lt;p&gt;We can also store a function literal inside a variable with a matching function type. Then you just pass that variable to the function like you would any other 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="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;myList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Anne"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chris"&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;myFilterFunctionVariable&lt;/span&gt;&lt;span class="p"&gt;:&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;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;str&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="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNotBlank&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&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;filterByFunctionVariable&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myList&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;myFilterFunctionVariable&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;"filterByFunctionVariable: [${filterByFunctionVariable.joinToString("&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="c1"&gt;// Output: &lt;/span&gt;
&lt;span class="c1"&gt;// filterByFunctionVariable: ["Leslie", "Chris"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Function Declarations to Function Types
&lt;/h3&gt;

&lt;p&gt;Lastly, we can take an existing, traditional declaration of a function and use the member reference operator (&lt;code&gt;::&lt;/code&gt;) to create an instance of a function type from the declaration.&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;myList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Anne"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chris"&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;myFilterPredicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&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;Boolean&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;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNotBlank&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&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;filterByNamedFunction&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myList&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="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;myFilterPredicate&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;"filterByNamedFunction: [${filterByNamedFunction.joinToString("&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="c1"&gt;// Output: &lt;/span&gt;
&lt;span class="c1"&gt;// filterByNamedFunction: ["Leslie", "Chris"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Receivers
&lt;/h2&gt;

&lt;p&gt;Receivers are something we use all the time, but we just don't think about it. Essentially, any time you are using dot notation to reference some member function for a specific instance of an object, you are using a receiver. For example, if we have &lt;code&gt;myObj.someFunction()&lt;/code&gt;, &lt;code&gt;myObj&lt;/code&gt; is considered the &lt;em&gt;receiver&lt;/em&gt; of the function call &lt;code&gt;someFunction&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each receiver has its own context and within that context &lt;code&gt;this&lt;/code&gt; references that specific object instance. Furthermore, inside a class, any reference to a member property or function always has an implicit &lt;code&gt;this&lt;/code&gt; attached to it. Although, for syntax convenience, we never have to type it.&lt;/p&gt;

&lt;p&gt;Now consider the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomObject&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="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getFormattedId&lt;/span&gt;&lt;span class="p"&gt;()&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;return&lt;/span&gt; &lt;span class="s"&gt;"MyCustomObject-${id}"&lt;/span&gt; &lt;span class="c1"&gt;// (implicit this reference for id)&lt;/span&gt;
        &lt;span class="c1"&gt;// or equivalently&lt;/span&gt;
        &lt;span class="c1"&gt;// return "MyCustomObject-${this.id}" (explicit this reference)&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;pawnee&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyCustomObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pawnee"&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;eagleton&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyCustomObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Eagleton"&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="n"&gt;pawnee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFormattedId&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// prints MyCustomObject-Pawnee&lt;/span&gt;
&lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eagleton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFormattedId&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// prints MyCustomObject-Eagleton&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we have &lt;code&gt;pawnee.getFormattedId()&lt;/code&gt;, the &lt;code&gt;pawnee&lt;/code&gt; instance variable is considered the receiver of the function call &lt;code&gt;getFormattedId&lt;/code&gt; and &lt;code&gt;this.id&lt;/code&gt; points to "&lt;em&gt;Pawnee&lt;/em&gt;". Likewise, when we have &lt;code&gt;eagleton.getFormattedId()&lt;/code&gt;, the &lt;code&gt;eagleton&lt;/code&gt; instance variable is now the receiver of that function call and &lt;code&gt;this.id&lt;/code&gt; points to "&lt;em&gt;Eagleton&lt;/em&gt;". This is how the &lt;code&gt;getFormattedId&lt;/code&gt; function knows which &lt;code&gt;id&lt;/code&gt; to get.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function Types with Receivers
&lt;/h2&gt;

&lt;p&gt;As we discussed earlier, &lt;code&gt;(A) -&amp;gt; B&lt;/code&gt; denotes a function type for a function that has one argument of type &lt;code&gt;A&lt;/code&gt; and has a return value of type &lt;code&gt;B&lt;/code&gt;. Optionally, a function type can also have a receiver type, which is defined with the following form:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;R.(A) -&amp;gt; B&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This represents a function that has one argument of type &lt;code&gt;A&lt;/code&gt; and has a return value of type &lt;code&gt;B&lt;/code&gt;, as before, but additionally is called on a receiver type &lt;code&gt;R&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example of a function that has a receiver with type &lt;code&gt;String&lt;/code&gt;, an argument with type &lt;code&gt;String&lt;/code&gt;, and that returns a type &lt;code&gt;Boolean&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;isLonger&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;String&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;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;other&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&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 then invoke this function by prepending a receiver to the function, similarly to how we invoke any other object's 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;result1_a&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="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isLonger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Anne"&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;ben&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result2_a&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="n"&gt;ben&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isLonger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Chris"&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;"Is Longer, Result1: $result1_a"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// true  &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;"Is Longer, Result2: $result2_a"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also invoke a function type with a receiver &lt;em&gt;without&lt;/em&gt; prepending the receiver, but instead, pass the receiver as the first argument to the 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;ben&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ben"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result1_b&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;isLonger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Anne"&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;result2_b&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="nf"&gt;isLonger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ben&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chris"&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;"Is Longer, Result1_b: $result1_b"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// true&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;"Is Longer, Result2_b: $result2_b"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result1_c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isLonger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Leslie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Anne"&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;result2_c&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="n"&gt;isLonger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ben&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chris"&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;"Is Longer, Result1_c: $result1_c"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// true&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;"Is Longer, Result2_c: $result2_c"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Comparison to Extension Functions
&lt;/h2&gt;

&lt;p&gt;Extension functions are full static function declarations with one implementation. When we create an extension function, the class isn't modified but instead the actual code compiles to a static function declaration. For example, when we define an extension function like:&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;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;countNumberOfVowels&lt;/span&gt;&lt;span class="p"&gt;()&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;vowels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Char&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;setOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'e'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'i'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'o'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'u'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'E'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'I'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'O'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'U'&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;count&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;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vowels&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;count&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;count&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;vowels&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, World"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;countNumberOfVowels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extension function definition and usage are syntactic sugar, and what the extension function ultimately gets resolved to 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="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;countNumberOfVowels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&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;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;vowels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Char&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;setOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'e'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'i'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'o'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'u'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'E'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'I'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'O'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'U'&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;count&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;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;word&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;char&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vowels&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;count&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;count&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;vowels&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;countNumberOfVowels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In fact, if you try and define both of these functions in the same package you will receive a build error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kotlin: Platform declaration clash: The following declarations have the same JVM signature (countNumberOfVowels(Ljava/lang/String;)I):&lt;/p&gt;

&lt;p&gt;fun countNumberOfVowels(word: String): Int defined in root package&lt;br&gt;&lt;br&gt;
fun String.countNumberOfVowels(): Int defined in root package&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Similarities
&lt;/h3&gt;

&lt;p&gt;Extension functions and function types with receivers are the same in that they are largely just syntactic sugar, and they both achieve the same thing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Extending the functionality of a class without actually modifying the class.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Providing a &lt;code&gt;this&lt;/code&gt; scope within the function literal so the user can implement the function literal as if it were a native member of the class.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Differences
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Extension functions are function declarations, and as the name implies, function types with receivers are just types, like any other type. In the case of higher-order functions, the type's implementation only gets defined when called.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We saw earlier that a function type with a receiver can be invoked with &lt;em&gt;and&lt;/em&gt; without specifying the receiver.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extension functions are a way to avoid having to resort to either inheritance, the decorator design pattern, or defining and using a bunch of util classes when extending a class' functionality. Function types with receivers are more concerned about making life easier when working with higher-order functions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;em&gt;Function types with receivers&lt;/em&gt; are a powerful feature and a key part of how Kotlin's &lt;code&gt;apply&lt;/code&gt;, &lt;code&gt;with&lt;/code&gt;, and &lt;code&gt;run&lt;/code&gt; scope functions work. It's a feature that allows for greater convenience and code clarity when developing in Kotlin.&lt;/p&gt;

&lt;p&gt;To fully understand this feature, we dove deeper into smaller concepts like &lt;em&gt;function types&lt;/em&gt; (learning how to define and use them), as well as &lt;em&gt;receivers&lt;/em&gt; (what they are and how they fit together with function types). Lastly, we looked at how a &lt;em&gt;function type with a receiver&lt;/em&gt; compares to and contrasts with an &lt;em&gt;extension function&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;If you noticed anything in the article that is incorrect or isn't clear, please let me know. I always appreciate the feedback.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>functions</category>
    </item>
  </channel>
</rss>
