<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:base="https://www.lordcodes.com/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Lord Codes » Android &amp; Kotlin Feed</title>
    <description>Lord Codes blog content on Android, Kotlin and other content aimed at Android developers. Learn about the basics and advanced topics to help you build better apps.</description>
    <link>https://www.lordcodes.com/android/</link>
    <atom:link href="https://www.lordcodes.com/android/rss.xml" rel="self" type="application/rss+xml" />
    <language>en_GB</language>    <item>
      <title>Embed a SearchBar into a TopAppBar in Jetpack Compose</title>
      <link>https://www.lordcodes.com/articles/compose-embed-searchbar-topappbar/</link>
      <description>
          &lt;p&gt;For many apps, search is a key part of creating a seamless and intuitive user experience. When it comes to building Android UIs with Compose, this can be achieved using the Material 3 &lt;code&gt;SearchBar&lt;/code&gt;. The search bar component allows us to build a bar that, when focused, expands into a search view to display suggestions or search results.&lt;/p&gt;&lt;p&gt;When used as it comes, the &lt;code&gt;SearchBar&lt;/code&gt; works nicely by itself and for large screens there is also a &lt;code&gt;DockedSearchBar&lt;/code&gt;. Most Android screens, however, include a &lt;code&gt;TopAppBar&lt;/code&gt; that has a background colour that changes when content scrolls behind it.&lt;/p&gt;&lt;p&gt;In this article, we will explore how to build a search experience and then how to embed it seamlessly into a &lt;code&gt;TopAppBar&lt;/code&gt;. This allows us to create a polished UI that&#39;s perfect for including search into any screen.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/d_W4hk63eV-814.webp 814w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/d_W4hk63eV-814.jpeg&quot; alt=&quot;SearchBar below the TopAppBar&quot; title=&quot;SearchBar below the TopAppBar&quot; class=&quot;article-img-medium&quot; width=&quot;814&quot; height=&quot;438&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;The problem&lt;/h2&gt;&lt;p&gt;As a starting point, we have a screen within our navigation hierarchy showing a list of projects. The projects list includes a &lt;code&gt;TopAppBar&lt;/code&gt; containing a navigation icon and title. We would like to be able to search across these projects, using a persistent search bar within the top bar, below the title.&lt;/p&gt;&lt;p&gt;When we add the search bar below our &lt;code&gt;TopAppBar&lt;/code&gt;, it is positioned correctly, however it is visually separate from the top bar.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/r3sxExqCjZ-750.webp 750w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/r3sxExqCjZ-750.jpeg&quot; alt=&quot;SearchBar below the TopAppBar&quot; title=&quot;SearchBar below the TopAppBar visually separated from the top bar&quot; class=&quot;article-img-medium&quot; width=&quot;750&quot; height=&quot;409&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;There are various changes we need to make so that it appears within the bar:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Add a surface behind the &lt;code&gt;SearchBar&lt;/code&gt; that matches the &lt;code&gt;TopAppBar&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Match the elevation behaviour, when content scrolls behind the &lt;code&gt;TopAppBar&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Apply styling when the &lt;code&gt;SearchBar&lt;/code&gt; expands into a search view.&lt;/li&gt;&lt;/ol&gt;&lt;h2 id=&quot;building-a-search-bar&quot; tabindex=&quot;-1&quot;&gt;Building a search bar&lt;/h2&gt;&lt;p&gt;Let&#39;s start by building our &lt;code&gt;SearchBar&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@Composable&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@OptIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExperimentalMaterial3Api&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;EmbeddedSearchBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    onQueryChange&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    isSearchActive&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    onActiveChanged&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    modifier&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Modifier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    onSearch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; searchQuery &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; rememberSaveable &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mutableStateOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 1&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; activeChanged&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; active &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
        searchQuery &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;onQueryChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;onActiveChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;active&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SearchBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; searchQuery&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// 2&lt;/span&gt;
        onQueryChange &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            searchQuery &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; query
            &lt;span class=&quot;token function&quot;&gt;onQueryChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// 3&lt;/span&gt;
        onSearch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onSearch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        active &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        onActiveChange &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; activeChanged&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// 4&lt;/span&gt;
        modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; modifier
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; top &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bottom &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillMaxWidth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        placeholder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Search&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        leadingIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                imageVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Icons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Rounded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Search&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                contentDescription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                tint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onSurfaceVariant&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// 5&lt;/span&gt;
        colors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SearchBarDefaults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            containerColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;surfaceContainerLow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        tonalElevation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Search suggestions or results&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;&lt;li&gt;When the search bar receives focus it becomes active and expands. At this point we clear the search term and report the active state change via the &lt;code&gt;onActiveChanged&lt;/code&gt; function. Note: if we wanted to keep the search term we wouldn&#39;t clear it here.&lt;/li&gt;&lt;li&gt;When the query changes we update the search term state and report the change via the &lt;code&gt;onQueryChange&lt;/code&gt; function.&lt;/li&gt;&lt;li&gt;The IME search triggers &lt;code&gt;onSearch&lt;/code&gt;. For now we are updating results whenever the query changes so are simply deactivating the search mode. If we were using a search API request we would perform the search here instead.&lt;/li&gt;&lt;li&gt;Add our search bar padding, sizing and other modifiers.&lt;/li&gt;&lt;li&gt;Style the search bar appearance, such as background colour.&lt;/li&gt;&lt;/ol&gt;&lt;h2 id=&quot;position-the-search-bar&quot; tabindex=&quot;-1&quot;&gt;Position the search bar&lt;/h2&gt;&lt;p&gt;The top of the screen is a &lt;code&gt;TopAppBar&lt;/code&gt; we have extracted out to &lt;code&gt;ProjectsTopAppBar&lt;/code&gt;, which is configured with a back button and title.&lt;/p&gt;&lt;details&gt;&lt;summary&gt;&lt;p&gt;Show code for &lt;code&gt;ProjectTopAppBar&lt;/code&gt;&lt;/p&gt;&lt;/summary&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@Composable&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@OptIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExperimentalMaterial3Api&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ProjectsTopAppBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    onBackClick&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    modifier&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Modifier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    scrollBehavior&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TopAppBarScrollBehavior&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;TopAppBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Projects&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; modifier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        navigationIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;IconButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;onClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onBackClick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    imageVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Icons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AutoMirrored&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Rounded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ArrowBack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    contentDescription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Back&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        colors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TopAppBarDefaults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;topAppBarColors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            navigationIconContentColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;primary&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        scrollBehavior &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scrollBehavior&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;p&gt;When using the Material 3 &lt;code&gt;Scaffold&lt;/code&gt; we can use a &lt;code&gt;Column&lt;/code&gt; to position the &lt;code&gt;SearchBar&lt;/code&gt; below the bar.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; isSearchActive &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; rememberSaveable &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mutableStateOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; scrollBehavior &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TopAppBarDefaults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pinnedScrollBehavior&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;Scaffold&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; modifier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    topBar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Column &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;ProjectsTopAppBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                onBackClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onBackClick&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                scrollBehaviour &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scrollBehavior&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;EmbeddedSearchBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                onQueryChange &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onQueryChange&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                isSearchActive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                onActiveChanged &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; isSearchActive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; it &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; contentPadding &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Search suggestions or results&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We now have a &lt;code&gt;SearchBar&lt;/code&gt; showing below our &lt;code&gt;TopAppBar&lt;/code&gt;, we next need to add a surface behind it so that it appears visually within the &lt;code&gt;TopAppBar&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/r3sxExqCjZ-750.webp 750w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/r3sxExqCjZ-750.jpeg&quot; alt=&quot;SearchBar below the TopAppBar&quot; title=&quot;SearchBar below the TopAppBar visually separated from the top bar&quot; class=&quot;article-img-medium&quot; width=&quot;750&quot; height=&quot;409&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=&quot;surface-behind-the-search-bar&quot; tabindex=&quot;-1&quot;&gt;Surface behind the search bar&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;TopAppBar&lt;/code&gt; is built with a surface that adapts its container colour based on the scroll behaviour applied to it. We can create a surface to display behind the &lt;code&gt;SearchBar&lt;/code&gt; that uses the same styling.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@OptIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExperimentalMaterial3Api&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@Composable&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TopAppBarSurface&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    modifier&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Modifier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 1&lt;/span&gt;
    colors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TopAppBarColors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TopAppBarDefaults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;topAppBarColors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 2&lt;/span&gt;
    scrollBehavior&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TopAppBarScrollBehavior&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token annotation builtin&quot;&gt;@Composable&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 3&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; colorTransitionFraction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scrollBehavior&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overlappedFraction &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0f&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; fraction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;colorTransitionFraction &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.01f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1f&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0f&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; appBarContainerColor &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;animateColorAsState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        targetValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            colors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;containerColor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            colors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;scrolledContainerColor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            FastOutLinearInEasing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fraction&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        animationSpec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stiffness &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Spring&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StiffnessMediumLow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        label &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;TopBarSurfaceContainerColorAnimation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Surface&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; modifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillMaxWidth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        color &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; appBarContainerColor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;&lt;li&gt;The same &lt;code&gt;TopAppBarColors&lt;/code&gt; we used in the &lt;code&gt;ProjectsTopAppBar&lt;/code&gt; above should be applied to this surface.&lt;/li&gt;&lt;li&gt;The same &lt;code&gt;TopAppBarScrollBehavior&lt;/code&gt; we pass into the &lt;code&gt;TopAppBar&lt;/code&gt; should be provided to the surface.&lt;/li&gt;&lt;li&gt;We can animate the container colour based on the scroll behaviour using the same approach as &lt;code&gt;TopAppBar&lt;/code&gt; uses internally.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;We can now wrap our search bar in the new &lt;code&gt;TopAppBarSurface&lt;/code&gt;, passing in the same scroll behaviour.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;topBar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;verticalArrangement &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Arrangement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spacedBy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;ProjectsTopAppBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            onBackClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onBackClick&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            scrollBehavior &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scrollBehavior&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;TopAppBarSurface&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scrollBehavior &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scrollBehavior&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;EmbeddedSearchBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                onQueryChange &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onQueryChange&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                isSearchActive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                onActiveChanged &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; isSearchActive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; it &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It seems to render with a tiny &lt;code&gt;1dp&lt;/code&gt; gap between the two bars, so &lt;code&gt;spacedBy((-1).dp)&lt;/code&gt; is included for vertical arrangement. If anyone can work out the cause of the 1dp gap please &lt;a href=&quot;https://x.com/lordcodes&quot;&gt;reach out&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/d_W4hk63eV-814.webp 814w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/d_W4hk63eV-814.jpeg&quot; alt=&quot;SearchBar below the TopAppBar&quot; title=&quot;SearchBar below the TopAppBar&quot; class=&quot;article-img-medium&quot; width=&quot;814&quot; height=&quot;438&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=&quot;active-search-view-styling&quot; tabindex=&quot;-1&quot;&gt;Active search view styling&lt;/h2&gt;&lt;p&gt;When the &lt;code&gt;SearchBar&lt;/code&gt; becomes active it expands to form a search view. We need to hide the &lt;code&gt;TopAppBar&lt;/code&gt; whilst search is active and also alter its appearance. We will make a few changes to the call to &lt;code&gt;SearchBar(...)&lt;/code&gt;.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;When search is active we need to remove the padding we applied earlier.&lt;/li&gt;&lt;li&gt;We can also animate the content size change to give a clean transition.&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    modifier
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animateContentSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stiffness &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Spring&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StiffnessHigh&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    modifier
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; top &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bottom &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillMaxWidth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animateContentSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stiffness &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Spring&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StiffnessHigh&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When active, we can replace the leading search icon with a back button to dismiss the search view.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;leadingIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;IconButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            onClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;activeChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                imageVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Icons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AutoMirrored&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Rounded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ArrowBack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                contentDescription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stringResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;navigation_action_back_cd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                tint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;primary&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            imageVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Icons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Rounded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Search&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            contentDescription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            tint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onSurfaceVariant&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After a query has been entered into the search view, we can show a clear button.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;trailingIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; searchQuery&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNotEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;IconButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            onClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                searchQuery &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;onQueryChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                imageVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Icons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Rounded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Close&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                contentDescription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stringResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search_text_field_clear&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                tint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;primary&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can tweak the background colour of the search view when it&#39;s active.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;colors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SearchBarDefaults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    containerColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;background
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;surfaceContainerLow
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As the search view is shown instead of the &lt;code&gt;TopAppBar&lt;/code&gt;, we need to apply its window insets.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;windowInsets &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    SearchBarDefaults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;windowInsets
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;WindowInsets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This completes our customisation of the active search view.&lt;/p&gt;&lt;details&gt;&lt;summary&gt;&lt;p&gt;Show full &lt;code&gt;EmbeddedSearchBar&lt;/code&gt; code&lt;/p&gt;&lt;/summary&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@Composable&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@OptIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExperimentalMaterial3Api&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;EmbeddedSearchBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    onQueryChange&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    isSearchActive&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    onActiveChanged&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    modifier&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Modifier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    onSearch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; searchQuery &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; rememberSaveable &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mutableStateOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; activeChanged&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; active &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
        searchQuery &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;onQueryChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;onActiveChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;active&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SearchBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; searchQuery&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        onQueryChange &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            searchQuery &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; query
            &lt;span class=&quot;token function&quot;&gt;onQueryChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        onSearch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onSearch &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;activeChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        active &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        onActiveChange &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; activeChanged&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            modifier
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animateContentSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stiffness &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Spring&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StiffnessHigh&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            modifier
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; top &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bottom &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillMaxWidth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animateContentSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stiffness &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Spring&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StiffnessHigh&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        placeholder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Search&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        leadingIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;IconButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    onClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;activeChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                        imageVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Icons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AutoMirrored&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Rounded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ArrowBack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        contentDescription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stringResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;navigation_action_back_cd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        tint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;primary&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    imageVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Icons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Rounded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Search&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    contentDescription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    tint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onSurfaceVariant&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        trailingIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; searchQuery&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNotEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;IconButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    onClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        searchQuery &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
                        &lt;span class=&quot;token function&quot;&gt;onQueryChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                        imageVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Icons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Rounded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Close&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        contentDescription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stringResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search_text_field_clear&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        tint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;primary&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        colors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SearchBarDefaults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            containerColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;background
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                MaterialTheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;colorScheme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;surfaceContainerLow
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        tonalElevation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        windowInsets &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isSearchActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            SearchBarDefaults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;windowInsets
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;WindowInsets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Search suggestions or results&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/vkFWHiyf2w-646.webp 646w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/vkFWHiyf2w-646.jpeg&quot; alt=&quot;Active search view&quot; title=&quot;Active search view&quot; class=&quot;article-img-medium&quot; width=&quot;646&quot; height=&quot;390&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;We have built a &lt;code&gt;SearchBar&lt;/code&gt; that appears embedded within a &lt;code&gt;TopAppBar&lt;/code&gt; that expands into a full-screen search view when focused. The &lt;code&gt;SearchBar&lt;/code&gt; is a very customisible component and Jetpack Compose makes it easy to achieve the design we want. This search bar component can now be used throughout our apps to add search to any screen we want.&lt;/p&gt;
      </description>
      <pubDate>Mon, 29 Jan 2024 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/compose-embed-searchbar-topappbar/</guid>
    </item>    <item>
      <title>Authorization and retrying of web requests for OkHttp and Retrofit</title>
      <link>https://www.lordcodes.com/articles/authorization-for-okhttp-retrofit/</link>
      <description>
          &lt;p&gt;Are you trying to set up authorization for your OkHttp or Retrofit web requests but aren&#39;t sure of the best way to do it? Have you explored &lt;code&gt;Interceptor&lt;/code&gt; and &lt;code&gt;Authenticator&lt;/code&gt; but aren&#39;t sure which to use or how best to use them? We will explore these concepts within OkHttp, how to sign web requests and also how to retry them if they fail due to a failed authorization attempt.&lt;/p&gt;&lt;p&gt;When setting up networking in our apps, authorization is almost always required, as not many remote APIs are completely un-authenticated. OAuth is a common system to use, relying on access tokens to protect our endpoints and refresh tokens to obtain new access tokens once they have expired. The idea is that the access token is added as an Authorization HTTP header on requests to let the API know we have access to a particular resource.&lt;/p&gt;&lt;p&gt;OkHttp provides &lt;code&gt;Interceptors&lt;/code&gt; which can alter web requests before they are sent out and &lt;code&gt;Authenticators&lt;/code&gt; that allow us to re-sign and retry requests that have failed due to authorization. It is very common, particularly on Android, to use Retrofit for networking, which uses OkHttp internally and so the same techniques apply to Retrofit as well.&lt;/p&gt;&lt;p&gt;Let&#39;s have a look at how we set this up and how it all works!&lt;/p&gt;&lt;h2 id=&quot;signing-requests&quot; tabindex=&quot;-1&quot;&gt;Signing requests&lt;/h2&gt;&lt;p&gt;We will start by setting up our &lt;code&gt;AuthorizationInterceptor&lt;/code&gt; that adds the &lt;code&gt;Authorization&lt;/code&gt; header to all web requests that are sent off to our remote API.&lt;/p&gt;&lt;p&gt;Our access tokens are provided by &lt;code&gt;AuthorizationRepository&lt;/code&gt;, which either provides a stored access token or obtains a new one if the stored one has already expired. How this process works depends on the authorization each particular API uses, the important part here is that &lt;code&gt;AuthorizationInterceptor&lt;/code&gt; has a function it can call to get an access token to sign the web request with.&lt;/p&gt;&lt;p&gt;Our &lt;code&gt;Interceptor&lt;/code&gt; implementation needs to provide an &lt;code&gt;intercept&lt;/code&gt; function that can extract the current &lt;code&gt;Request&lt;/code&gt;, transform it and then pass this new request back into the chain. The transformation we need to apply involves adding an Authorization header that signs the request with our access token. It is worth noting that the exact format of the header may change depending on what type of tokens each API uses, in our example Bearer tokens are used which are pretty common.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AuthorizationInterceptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; authorizationRepository&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthorizationRepository
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Interceptor &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;intercept&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Interceptor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Chain&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Response &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; newRequest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; chain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signedRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; chain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;proceed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signedRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; accessToken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; authorizationRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetchFreshAccessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;newBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bearer &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rawToken&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Registering our interceptor just involves adding it to the builder we are using to create our &lt;code&gt;OkHttpClient&lt;/code&gt; for either use directly or with Retrofit.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;okHttpClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;authorizationInterceptor&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthorizationInterceptor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    OkHttpClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addInterceptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;authorizationInterceptor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All outgoing web requests will now be signed with our access token.&lt;/p&gt;&lt;h2 id=&quot;retrying-failed-requests&quot; tabindex=&quot;-1&quot;&gt;Retrying failed requests&lt;/h2&gt;&lt;p&gt;It is possible that our requests may fail with &lt;code&gt;401 Unauthorized&lt;/code&gt; due to an issue with the access token we provided. This will usually be due to the access token having expired or being revoked on the server-side. To handle this situation we can build an OkHttp &lt;code&gt;Authenticator&lt;/code&gt;, that allows us to catch this case, add a new token and then retry the request.&lt;/p&gt;&lt;p&gt;We will start by extracting an extension function to set the Authorization header on a request.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signWithToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;accessToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AccessToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;newBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bearer &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rawToken&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We will build in a limit on the number of retries to avoid an infinite loop if authorization for a particular endpoint fails entirely. We can determine how many times a request has been retried from the response.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; Response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retryCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Int
    &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; currentResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; priorResponse
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentResponse &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            result&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;
            currentResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;priorResponse
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The implementation of &lt;code&gt;Authenticator&lt;/code&gt; receives the response that failed with &lt;code&gt;401 Unauthorized&lt;/code&gt; and has to optionally provide a new request to be triggered. If our request has already been retried twice we will simply allow it to fail to avoid an infinite loop. Signing the request is done in the same way as in our &lt;code&gt;AuthorizationInterceptor&lt;/code&gt; above.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TokenRefreshAuthenticator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; authorizationRepository&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthorizationRepository
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Authenticator &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        route&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Route&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        response&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Response
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retryCount &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createSignedRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createSignedRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; accessToken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; authenticationRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetchFreshAccessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signWithToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Throwable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Failed to re-sign request&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Registering our authenticator involves adding it to the builder alongside our interceptor.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;OkHttpClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addInterceptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;authorizationInterceptor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;authenticator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tokenRefreshAuthenticator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Web requests that fail with authorization issues will now be re-signed and retried!&lt;/p&gt;&lt;h2 id=&quot;refreshing-expired-tokens&quot; tabindex=&quot;-1&quot;&gt;Refreshing expired tokens&lt;/h2&gt;&lt;p&gt;In the above &lt;code&gt;AuthorizationInterceptor&lt;/code&gt; and &lt;code&gt;TokenRefreshAuthenticator&lt;/code&gt; we obtain an access token using &lt;code&gt;fetchFreshAccessToken&lt;/code&gt;. This function has been built to return the stored access token if it hasn&#39;t expired yet or to obtain a new one if it has.&lt;/p&gt;&lt;p&gt;An important note is that the function signatures of both &lt;code&gt;Interceptor&lt;/code&gt; and &lt;code&gt;Authenticator&lt;/code&gt; require the request to be created or transformed synchronously. The process of refreshing an access token is likely asynchronous due to requiring its own web request to an OAuth API. We therefore need to call this asynchronous token refresh process synchronously, exactly how will depend on how on it is implemented.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Kotlin Coroutines can use the &lt;a href=&quot;https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html&quot;&gt;runBlocking function&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Retrofit Call has a synchronous &lt;a href=&quot;https://square.github.io/retrofit/2.x/retrofit/retrofit2/Call.html#execute--&quot;&gt;execute function&lt;/a&gt;&lt;/li&gt;&lt;li&gt;RxJava Single has a synchronous &lt;a href=&quot;http://reactivex.io/RxJava/javadoc/io/reactivex/Single.html#blockingGet--&quot;&gt;blockingGet operator&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;multiple-authorization-types&quot; tabindex=&quot;-1&quot;&gt;Multiple authorization types&lt;/h2&gt;&lt;p&gt;In our implementation so far we have assumed that all requests need to be signed in the same way, however, in reality this likely won&#39;t be the case. For example, there will likely be requests that need to be performed before a user has signed in such as the account creation request or maybe fetching some form of configuration.&lt;/p&gt;&lt;p&gt;To incorporate this, we can use the OkHttp Tag API, which can also be used in our Retrofit calls. We will tag our web requests with an &lt;code&gt;AuthType&lt;/code&gt; enum that specifies which type of authorization to be used.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; AuthType &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ACCESS_TOKEN&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    CLIENT_CREDENTIALS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    NONE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;companion&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fromRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;AuthType&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; ACCESS_TOKEN
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With OkHttp the tag can be specified in the request builder and with Retrofit it can be added using an annotation for a particular call.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; CreateAccountRemoteApi &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation builtin&quot;&gt;@POST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;user/identity&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;suspend&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createAccount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token annotation builtin&quot;&gt;@Body&lt;/span&gt; request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateAccountRemoteDto&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token annotation builtin&quot;&gt;@Tag&lt;/span&gt; authorization&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CLIENT_CREDENTIALS
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AccountCreatedRemoteDto
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;AuthType&lt;/code&gt; can now be extracted and used within our &lt;code&gt;AuthorizationInterceptor&lt;/code&gt; and &lt;code&gt;TokenRefreshAuthenticator&lt;/code&gt;, to decide how to sign the request.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AuthorizationInterceptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; authorizationRepository&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthorizationRepository
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Interceptor &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;intercept&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Interceptor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Chain&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Response &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; newRequest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; chain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signedRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; chain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;proceed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signedRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;AuthType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        AuthType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ACCESS_TOKEN &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;signWithFreshAccessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        AuthType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CLIENT_CREDENTIALS &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;signWithClientCredentialsToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        AuthType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NONE &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using this approach we can easily control the exact type of authorization each individual endpoint requires, giving us a great level of flexibility.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Adding authorization to web requests for OkHttp and Retrofit can be done without too much complexity, however, without knowing which parts of the API to use it may not be immediately obvious. By using an &lt;code&gt;Interceptor&lt;/code&gt; we can avoid requests failing due to being unauthorized and then we can combine this with an &lt;code&gt;Authenticator&lt;/code&gt; to also handle the cases where it does unfortunately fail.&lt;/p&gt;
      </description>
      <pubDate>Tue, 17 Mar 2020 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/authorization-for-okhttp-retrofit/</guid>
    </item>    <item>
      <title>The power of lazy properties in Kotlin</title>
      <link>https://www.lordcodes.com/articles/the-power-of-lazy-properties-in-kotlin/</link>
      <description>
          &lt;p&gt;Do you have properties in your Kotlin types that you want to create later after initialization? You may want to avoid making them nullable, avoid using &lt;code&gt;lateinit&lt;/code&gt; or delay an expensive set up process to a later point. In Kotlin this is where &lt;a href=&quot;https://kotlinlang.org/docs/reference/delegated-properties.html&quot;&gt;delegated properties&lt;/a&gt; and &lt;a href=&quot;https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/lazy.html&quot;&gt;lazy properties&lt;/a&gt; in particular can be used, allowing properties to be initialized when they are needed and even keep our main type&#39;s initialization simpler and cleaner.&lt;/p&gt;&lt;p&gt;The idea of making a property &lt;em&gt;lazy&lt;/em&gt; is not new to Kotlin and many developers having been doing it in other languages or doing it themselves for ages. There were common approaches to a form of lazy creation in Java, it was hard to live in the Java world without coming across a &lt;code&gt;getInstance()&lt;/code&gt; function at some point!&lt;/p&gt;&lt;p&gt;When it comes to defining lazy properties in Kotlin, they have been brought into being part of the language. There is some new syntax, some different options for initializing them and various situations in which they can be really useful. Let&#39;s take a look!&lt;/p&gt;&lt;h2 id=&quot;creating-them&quot; tabindex=&quot;-1&quot;&gt;Creating them&lt;/h2&gt;&lt;p&gt;Creating a lazy property in Kotlin is pretty simple, we define it using &lt;code&gt;by lazy&lt;/code&gt; and provide a function initializer. At a later point, when the property is first accessed it will be initialized using the function we provided and then on future accesses the cached value will be returned instead. Nifty!&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; bindingController &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; lazy &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;FilesBindingController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viewModel&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;onFileOpened&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our &lt;code&gt;bindingController&lt;/code&gt; property needs to access the &lt;code&gt;viewModel&lt;/code&gt; property in order to be created and so by making it lazy, this can be deferred until it is first used. After &lt;code&gt;bindingController&lt;/code&gt; has been initialized, the value will simply be returned every time from then on.&lt;/p&gt;&lt;h2 id=&quot;factory-method&quot; tabindex=&quot;-1&quot;&gt;Factory method&lt;/h2&gt;&lt;p&gt;Creating our property may not always be as simple as just calling an initializer and more code may be needed to set it up. In these situations we may wish to move the contents of the lazy function initializer to a factory method on the outer class.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TeamRepository&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appSchedulers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AppSchedulers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; viewState &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;createViewStateLiveData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createViewStateLiveData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LiveData&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ViewState&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
      teamRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;teamMembersStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;mapPresentingState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;onErrorReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;mapErrorState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ViewState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Loading&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribeOn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appSchedulers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;io&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observeOn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appSchedulers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLiveData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Moving the initialization code to a factory method can keep the top of our class cleaner and we may find we prefer to keep this set up code out of the way. In some situations we may even be able to use a separate factory object to move the initialization logic to another type or file if we wanted to.&lt;/p&gt;&lt;h2 id=&quot;extension&quot; tabindex=&quot;-1&quot;&gt;Extension&lt;/h2&gt;&lt;p&gt;Across our codebase there will be common situations for using lazy properties and so to simplify the call sites we may decide to use an extension function. For example, when using Android &lt;code&gt;ViewModel&lt;/code&gt;, each of our Activities will need to retrieve their View Model, which can be done using an extension function on a common base class.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;reified&lt;/span&gt; ViewModelT &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ViewModel&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ComponentActivity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bindViewModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;bindViewModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ViewModelT&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; viewModelFactoryProvider&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token annotation builtin&quot;&gt;@PublishedApi&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ViewModelT &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ViewModel&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ComponentActivity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bindViewModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    viewModelType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; KClass&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ViewModelT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Lazy&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ViewModelT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; lazy &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;ViewModelProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viewModelType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using our new lazy extension function cleans up the initialization call site.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; TeamActivity &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FragmentActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; viewModel&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TeamViewModel &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bindViewModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This particular example is now provided by the &lt;a href=&quot;https://developer.android.com/reference/kotlin/androidx/activity/package-summary#(androidx.activity.ComponentActivity).viewModels(kotlin.Function0)&quot;&gt;AndroidX Activity library&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;how-does-it-work%3F&quot; tabindex=&quot;-1&quot;&gt;How does it work?&lt;/h2&gt;&lt;p&gt;Delegated properties work as their name suggests, delegating the property&#39;s getter and maybe setter to another type. There are a selection of different delegated property types provided and then on top of this we can write our own. The expression we place after the &lt;code&gt;by&lt;/code&gt; keyword is what specifies the delegate that will be used.&lt;/p&gt;&lt;p&gt;In the case of &lt;code&gt;by lazy&lt;/code&gt;, a &lt;code&gt;Lazy&lt;/code&gt; delegate type will control access to our property, initializing it on first access and then returning the cached value on subsequent accesses. Users of the property don&#39;t need to change how they call it, meaning the read-write behaviour of our property can be changed at the property definition without affecting code that uses it.&lt;/p&gt;&lt;h2 id=&quot;multithreading&quot; tabindex=&quot;-1&quot;&gt;Multithreading&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;lazy&lt;/code&gt; function has an argument with a default value that controls its synchronization behaviour. If a lazy property is accessed from multiple threads concurrently, synchronization will need to be handled by choosing an appropriate &lt;code&gt;LazyThreadSafetyMode&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; messageId &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LazyThreadSafetyMode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NONE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createMessageId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The default value &lt;code&gt;SYNCHRONIZED&lt;/code&gt; will ensure only a single thread can initialize the property using locks. If we are sure the property will only be accessed by a single thread we can switch to &lt;code&gt;NONE&lt;/code&gt; to avoid the overhead of performing the synchronization. There is also the option of using &lt;code&gt;PUBLICATION&lt;/code&gt; which allows multiple threads to call the initializer, but only the first returned value being used.&lt;/p&gt;&lt;p&gt;Most UI code, such as in an &lt;code&gt;Activity&lt;/code&gt; or &lt;code&gt;Fragment&lt;/code&gt;, will run on the UI thread and so properties that are only used here can use the &lt;code&gt;LazyThreadSafetyMode.NONE&lt;/code&gt;. We could even add an extension to avoid specifying this each time.&lt;/p&gt;&lt;h2 id=&quot;other-use-cases&quot; tabindex=&quot;-1&quot;&gt;Other use cases&lt;/h2&gt;&lt;p&gt;Lazy is useful wherever we want to delay initialization to a later point, rather than doing it straight away. Without it other options may include a &lt;code&gt;lateinit&lt;/code&gt; property which simply &amp;quot;promises&amp;quot; to be initialized before it is used or a nullable property which can have a value or not.&lt;/p&gt;&lt;p&gt;When we just want to delay initialization, lazy can be a nicer approach to the alternatives. It can be especially helpful for obtaining dependencies whose initialization is out of our control, such as Android View Models from an Activity or Fragment.&lt;/p&gt;&lt;p&gt;There are times when we need to read a value from somewhere, but don&#39;t want it to be retrieved again each time it is needed. An example is reading &lt;code&gt;Bundle&lt;/code&gt; extras from an &lt;code&gt;Intent&lt;/code&gt;, where using a lazy property would mean on first access the value is read from the &lt;code&gt;Intent&lt;/code&gt; and then cached for quicker access in the future.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; OrderDetailActivity &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FragmentActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; orderId &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; lazy &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      intent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getParcelableExtra&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;OrderId&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EXTRA_ORDER_ID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Delegated properties and lazy properties in particular are a great feature to have at our disposal. The give us flexibility over how our properties are initialized and accessed. It is really nice to be able to make a property lazy without having to alter how it is used in calling code.&lt;/p&gt;
      </description>
      <pubDate>Sun, 01 Mar 2020 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/the-power-of-lazy-properties-in-kotlin/</guid>
    </item>    <item>
      <title>Uploading a file with progress in Kotlin</title>
      <link>https://www.lordcodes.com/articles/uploading-a-file-with-progress-in-kotlin/</link>
      <description>
          &lt;p&gt;Do you want to upload a file using the clean Retrofit syntax, but aren&#39;t sure how to receive the result as well as the upload progress? We will be using Retrofit to perform the file upload, building an implementation that is able to receive the completion progress at intervals and then complete with the remote API response.&lt;/p&gt;&lt;p&gt;Whilst long-running operations are happening, it is nice for the user to see that activity is occurring, such as a progress view being displayed. For the case of a file upload we can show the real progress, which can be represented by the number of bytes transmitted out of the total file size.&lt;/p&gt;&lt;p&gt;We will use the APIs available to us in &lt;a href=&quot;https://square.github.io/retrofit/&quot;&gt;Retrofit&lt;/a&gt;, &lt;a href=&quot;https://square.github.io/okhttp/&quot;&gt;OkHttp&lt;/a&gt; and &lt;a href=&quot;https://square.github.io/okio/&quot;&gt;Okio&lt;/a&gt; to build a class that can be used whenever we want a request to publish its progress to whoever wishes to observe it!&lt;/p&gt;&lt;h2 id=&quot;endpoint&quot; tabindex=&quot;-1&quot;&gt;Endpoint&lt;/h2&gt;&lt;p&gt;We are developing a messaging application that is able to attach a file to a message thread. It is worth noting that we are using Kotlin Coroutines, however, it can be altered to use regular callbacks or a reactive framework such as RxJava.&lt;/p&gt;&lt;p&gt;Our endpoint is a POST request that contains a multipart body, consisting of the filename, file MIME type, file size and the file itself. We can define it using Retrofit, specifying the required parts.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@Multipart&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@POST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;suspend&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;uploadFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token annotation builtin&quot;&gt;@Part&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; filename&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token annotation builtin&quot;&gt;@Part&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; mimeType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token annotation builtin&quot;&gt;@Part&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; fileSize&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token annotation builtin&quot;&gt;@Part&lt;/span&gt; filePart&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MultipartBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Part&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FileUploadedRemoteDto&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;counting-progress&quot; tabindex=&quot;-1&quot;&gt;Counting progress&lt;/h2&gt;&lt;p&gt;If we just wanted to upload the file without any progress, we would simply convert the file to a request body and send it in the request.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUploadRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; File&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mimeType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mimeType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMediaType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Monitoring upload progress can be achieved by using our own &lt;code&gt;CountingRequestBody&lt;/code&gt; which wraps around the file &lt;code&gt;RequestBody&lt;/code&gt; that would have been used before. The data that is transmitted is the same as before, allowing the raw file &lt;code&gt;RequestBody&lt;/code&gt; to be delegated to for the content type and content length.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CountingRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; requestBody&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; onProgressUpdate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CountingRequestListener&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;RequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requestBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token annotation builtin&quot;&gt;@Throws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IOException&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contentLength&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requestBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contentLength&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Transmitting the request body is performed by writing it to a &lt;code&gt;Sink&lt;/code&gt;, we will wrap the default sink with our own one that counts the bytes that are transmitted and reports them back via a progress callback.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typealias&lt;/span&gt; CountingRequestListener &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    bytesWritten&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Long&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    contentLength&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Long&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CountingSink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    sink&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Sink&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; requestBody&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; onProgressUpdate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CountingRequestListener&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ForwardingSink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; bytesWritten &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0L&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;source&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; byteCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Long&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;source&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; byteCount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        bytesWritten &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; byteCount
        &lt;span class=&quot;token function&quot;&gt;onProgressUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            bytesWritten&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            requestBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contentLength&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Within &lt;code&gt;CountingRequestBody&lt;/code&gt; we can wrap the default sink into our new &lt;code&gt;CountingSink&lt;/code&gt; and write to a buffered version of that, in order to both transmit the file and observe its progress.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CountingRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; requestBody&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; onProgressUpdate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CountingRequestListener&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;RequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requestBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token annotation builtin&quot;&gt;@Throws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IOException&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contentLength&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requestBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contentLength&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token annotation builtin&quot;&gt;@Throws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IOException&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;writeTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sink&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; BufferedSink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; countingSink &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CountingSink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sink&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; onProgressUpdate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; bufferedSink &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; countingSink&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        requestBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bufferedSink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        bufferedSink&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;the-result&quot; tabindex=&quot;-1&quot;&gt;The result&lt;/h2&gt;&lt;p&gt;Whilst observing the upload progress, there will either be progress or a completed response, the perfect candidate for a sealed class. This will allow &lt;code&gt;CountingRequestResult&lt;/code&gt; to be the return type and callers can handle both progress updates and the completed result.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; CountingRequestResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ResultT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; Progress&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ResultT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; progressFraction&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Double
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CountingRequestResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ResultT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; Completed&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ResultT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; result&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ResultT
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CountingRequestResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ResultT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;perform-the-upload&quot; tabindex=&quot;-1&quot;&gt;Perform the upload&lt;/h2&gt;&lt;p&gt;Now that we have a way of uploading a file and receiving the upload progress, we can write our &lt;code&gt;FileUploader&lt;/code&gt;. Creating the request body for our upload request involves using a &lt;code&gt;CountingRequestBody&lt;/code&gt; that reports progress and completion to a &lt;code&gt;MutableStateFlow&lt;/code&gt; (or another reactive type).&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUploadRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    file&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; File&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    mimeType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    progressEmitter&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MutableStateFlow&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Double&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestBody &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; fileRequestBody &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mimeType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMediaType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CountingRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fileRequestBody&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; bytesWritten&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; contentLength &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; progress &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bytesWritten &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; contentLength
        progressEmitter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; progress &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The upload request consists of using the Retrofit function we implemented at the beginning, providing the file details and the created request body that will count progress. The Retrofit definition and the format of the request parts will depend on how each particular API is put together. Here we are using a request that contains various plaintext parts for the file details and then one for the file to be uploaded.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;suspend&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;performFileUpload&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    filename&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    file&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; File&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    mimeType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    progressEmitter&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MutableStateFlow&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Double&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FileUploadedRemoteDto &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; requestBody &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUploadRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mimeType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; progressEmitter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; remoteApi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;uploadFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        filename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; filename&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMediaType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        mimeType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mimeType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMediaType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        fileSize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; file
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toRequestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMediaType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        filePart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MultipartBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Part&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createFormData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;files[]&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            filename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requestBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our main upload function can put together all of these parts to create a single result flow. We will be able to collect this to get progress updates as well as the final result.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;uploadFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    filename&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    file&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; File&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    mimeType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Flow&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;FileUploadRemoteResult&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; progressEmitter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MutableStateFlow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; progressStream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; progressEmitter
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transformWhile&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Double&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FileUploadRemoteResult&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; progress &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CountingRequestResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Progress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;progress&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            progress &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; resultStream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; uploadResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;performFileUpload&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            mimeType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            progressEmitter&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CountingRequestResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Completed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;uploadResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;progressStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resultStream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typealias&lt;/span&gt; FileUploadRemoteResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; CountingRequestResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;FileUploadedRemoteDto&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can now upload a file to our API and update a view as the request progresses, which is nice for noticeably long operations like uploading larger files.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;uploader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;uploadFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mimeType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;distinctUntilChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; uploadResult &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Update progress in UI&lt;/span&gt;
        fileUploadingState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inProgressState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;uploadResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Get uploaded file&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;uploadResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; CountingRequestResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Completed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            uploadedFileState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; uploadResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Monitoring the progress of a web request may not be immediately obvious when reading through the Retrofit API, however, the powerful APIs of OkHttp and Okio can get the job done nicely. The solution we have developed can be used for any web request, as the counting process can be wrapped around any &lt;code&gt;RequestBody&lt;/code&gt; that needs to be sent in a request.&lt;/p&gt;
      </description>
      <pubDate>Tue, 25 Feb 2020 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/uploading-a-file-with-progress-in-kotlin/</guid>
    </item>    <item>
      <title>Simplified launching of Android Activities</title>
      <link>https://www.lordcodes.com/articles/simplified-launching-of-android-activities/</link>
      <description>
          &lt;p&gt;Extension functions are really great for making life easier, allowing us to add functionality to types that aren&#39;t our own. One area we can use an extension is for launching Android Activities more easily.&lt;/p&gt;&lt;p&gt;We can build an extension that allows all Activities to be launched via a generic type argument. An optional request code can be passed to the function, which controls whether &lt;code&gt;startActivity&lt;/code&gt; or &lt;code&gt;startActivityForResult&lt;/code&gt; is used to launch the Activity. By providing an intent builder function, the &lt;code&gt;Intent&lt;/code&gt; that is fired can be customised.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;reified&lt;/span&gt; ActivityT &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Activity&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Activity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    requestCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Int&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    intentBuilder&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Intent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; intent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Intent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ActivityT&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;intentBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;requestCode &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;startActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;intent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;startActivityForResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;intent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; requestCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;startContactCreation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fromActivity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Activity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; requestCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Int&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    fromActivity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;startActivity&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ConnectionCreationActivity&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;requestCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;putExtra&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ConnectionCreationSource&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CONNECTIONS&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
      </description>
      <pubDate>Tue, 25 Feb 2020 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/simplified-launching-of-android-activities/</guid>
    </item>    <item>
      <title>Protecting secrets in an Android project</title>
      <link>https://www.lordcodes.com/articles/protecting-secrets-in-an-android-project/</link>
      <description>
          &lt;p&gt;Would you like to include secrets such as API keys into your Android project, but also want to protect them and keep them safe? We can use features of Gradle, environment variables, obfuscation and encryption, to keep them out of Git and to keep them secure.&lt;/p&gt;&lt;p&gt;When developing apps we will often need to use secret values that we don&#39;t want anyone to get access to, such as tokens, IDs and API keys. There are many reasons they may be needed in our source code and in Gradle scripts, the most common being when we are asked to provide one to authenticate with a third-party API.&lt;/p&gt;&lt;p&gt;We will examine a selection of techniques that we can apply, providing protection for our secrets and preventing them from sitting in plaintext, in plain sight!&lt;/p&gt;&lt;h2 id=&quot;why&quot; tabindex=&quot;-1&quot;&gt;Why&lt;/h2&gt;&lt;p&gt;When following the set up instructions to integrate a new library, we are usually told to put the API key in the &lt;code&gt;AndroidManifest.xml&lt;/code&gt;, in the source code or in a Gradle file. These suggestions will result in the secrets being added to source control and to be easily obtainable in plaintext by decompiling our app.&lt;/p&gt;&lt;p&gt;There are more secure ways of managing our secrets and through these tips we can make them significantly harder to obtain. It is worth remembering that our app is published and installed, meaning people will be able to take it apart and try and find secret values within it. All we can do as developers is to apply an appropriate level of security and do our best to keep these secrets safe. When it comes to API keys and tokens, there are also techniques that can be applied on the backend-side to detect fraudulent use and block access using those credentials.&lt;/p&gt;&lt;h2 id=&quot;where-to-store-them&quot; tabindex=&quot;-1&quot;&gt;Where to store them&lt;/h2&gt;&lt;p&gt;Gradle allows values to be passed in via Gradle properties, these can be passed on the command line or stored in a project-level or user-level properties file. A great way to handle our secrets is to use the user-level file on our filesystem, keeping them out of the project and out of source control. If we were to remove the project from our system and then re-clone it the secrets would still be there and we also have the possibility to include the same secrets into multiple projects without requiring extra set up.&lt;/p&gt;&lt;p&gt;By storing them at a user-level and keeping them out of Git, it means everyone with read-access to the source code doesn&#39;t automatically receive the secrets and if our source control system was compromised the attackers wouldn&#39;t obtain all of our secrets alongside the source code.&lt;/p&gt;&lt;p&gt;The file is stored within our user directory:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;On Mac or Linux: &lt;code&gt;/Users/&amp;lt;you&amp;gt;/.gradle/gradle.properties&lt;/code&gt;&lt;/li&gt;&lt;li&gt;On Windows: &lt;code&gt;C:&#92;Users&#92;&amp;lt;you&amp;gt;&#92;.gradle&#92;gradle.properties&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We add a property for each secret to the file, keeping in mind it is user-level and so we will want something to signify which app or project the secret corresponds to.&lt;/p&gt;&lt;pre class=&quot;language-properties&quot;&gt;&lt;code class=&quot;language-properties&quot;&gt;&lt;span class=&quot;token key attr-name&quot;&gt;GameCatalogueApp_UploadKeystore_KeyPassword&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;aaaabbbbcccc&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;GameCatalogueApp_AuthClientSecret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;123456789&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;GameCatalogueApp_Pusher_APIKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;ksldjalksdjskald&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;using-values&quot; tabindex=&quot;-1&quot;&gt;Using values&lt;/h2&gt;&lt;p&gt;Accessing the values within our Android project is as simple as reading them as a Gradle property and using them how we wish. If the value is needed within a Gradle script, such as to pass in a keystore password, it can just be read and used as it is. We are using a handy extension to get the property and return an empty string if it isn&#39;t present, to avoid the null value. If our secrets are set up correctly, they won&#39;t be missing.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;signingConfigs &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;upload&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    storePassword &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;propertyOrEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;GameCatalogueApp_UploadKeystore_KeyPassword&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;propertyOrEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; property &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; property &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using the values from our source code requires them to be passed through using either &lt;code&gt;resValue&lt;/code&gt; or &lt;code&gt;buildConfigField&lt;/code&gt;, depending on whether we want them as an Android resource or as a property on the &lt;code&gt;BuildConfig&lt;/code&gt; object. One quirk with &lt;code&gt;buildConfigField&lt;/code&gt; is the String containing the property value needs to have quotes within it, in order for &lt;code&gt;BuildConfig&lt;/code&gt; to be correctly generated.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;defaultConfig &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;buildConfigField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;String&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;AUTH_CLIENT_SECRET&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;buildConfigProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;GameCatalogueApp_AuthClientSecret&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;resValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pusher_key&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;propertyOrEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;GameCatalogueApp_Pusher_APIKey&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;buildConfigProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;propertyOrEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#92;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;what-about-ci&quot; tabindex=&quot;-1&quot;&gt;What about CI&lt;/h2&gt;&lt;p&gt;It would be very common for our project to be built on a continuous integration (CI) system or service, such as Bitrise or Jenkins. If this is the case we will need our secrets to be available on CI and passed through to the build environment. A handy trick here is that we can set the secrets as environment variables that use the same names as the Gradle properties. The functions we use to read their values within Gradle can then check for both a Gradle property or an environment variable and use whichever is found.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;propertyOrEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; property &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; property &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;environmentVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;environmentVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; System&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of course, this means environment variables can also be used locally if we would prefer, however, using Gradle properties is a very simple process.&lt;/p&gt;&lt;h2 id=&quot;encrypt-them&quot; tabindex=&quot;-1&quot;&gt;Encrypt them&lt;/h2&gt;&lt;p&gt;Even though our secrets are now usable and kept separate to the source code, it would still be fairly simple to decompile the app and extract our secrets in plain text. We can take our solution further by encrypting the values before they are stored and then decrypting them at runtime.&lt;/p&gt;&lt;p&gt;There are various options for encryption, including built-in options or third-party libraries. One possibility is &lt;a href=&quot;https://github.com/cossacklabs/themis&quot;&gt;Themis&lt;/a&gt;, which is easy to use and provides strong cryptographic techniques, along with a unified API between Android and iOS. Unless there is a skilled cryptographer working on the project, it may be a good idea to use a higher-level encryption API to avoid mistakes being made which weaken applied security measures.&lt;/p&gt;&lt;p&gt;In order to encrypt our data we will need an encryption key.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;GameCatalogueApp_EncryptionKey&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;super_secret_key

&lt;span class=&quot;token function&quot;&gt;buildConfigField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;String&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ENCRYPTION_KEY&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;buildConfigProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;GameCatalogueApp_EncryptionKey&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can provide some obfuscation and protection to our key by applying runtime transformations to it, resulting in the &amp;quot;real&amp;quot; key we will actually use. By doing this an attacker would need to decompile the source code and work out from the obfuscated code which operations were applied to the key.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ByteArray &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; rawKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;buildString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;byteArrayOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x27&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;base64EncodedString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;89&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BuildConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ENCRYPTION_KEY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pghy^%£aft&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; rawKey&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toByteArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; ByteArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;base64EncodedString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Base64&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encodeToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Base64&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NO_WRAP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we have only applied some fairly simple operations onto the key to demonstrate the idea, the concept could be taken much further and make the key harder to crack.&lt;/p&gt;&lt;p&gt;Now that we have our encryption key ready to go, we can use a Themis &lt;code&gt;SecureCell&lt;/code&gt; to turn our raw String data into an encrypted byte string.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;encrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ByteArray &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; encryptionKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; cell &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SecureCell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;encryptionKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SecureCell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MODE_SEAL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; protectedData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;protect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        encryptionContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toByteArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; protectedData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;protectedData
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; encryptionContext&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ByteArray&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To store our encrypted secret we can encode the produced &lt;code&gt;ByteArray&lt;/code&gt; into a base 64 encoded string. The same key generation code could be added to a script or we could just run the app, encrypt the secret and print out the value for us to copy.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; encypted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;EncryptionEngine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;raw_secret_value&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
Log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ENCRYPTED&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; encypted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;base64EncodedString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Gradle properties or our CI environment variables can now be replaced with encrypted versions.&lt;/p&gt;&lt;h2 id=&quot;decrypt-them&quot; tabindex=&quot;-1&quot;&gt;Decrypt them&lt;/h2&gt;&lt;p&gt;At runtime we will first need to convert the base 64 encoded version into an encrypted &lt;code&gt;ByteArray&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; encryptedDaya &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Base64&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;secretAsBase64&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Base64&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NO_WRAP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The encrypted &lt;code&gt;ByteArray&lt;/code&gt; now needs to be turned into the raw string versions, using the same encryption key as was used for the encryption process earlier. We will need to handle a failed decryption in some way, which would mean something had been set up incorrectly or an invalid value was passed in.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;decrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;encryptedData&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ByteArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; encryptionKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; cell &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SecureCell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;encryptionKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SecureCell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MODE_SEAL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; cellData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SecureCellData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;encryptedData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; decodedData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unprotect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;encryptionContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cellData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;decodedData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SecureCellException&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EncryptionEngine&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &quot;Failed &lt;span class=&quot;token keyword&quot;&gt;to&lt;/span&gt; decrypt message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our unencrypted secrets can now be used as they were before. It can be a good practice to decrypt them when they need to be used rather than storing them in an unencrypted state during an app session.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Protecting our API keys and other secrets is a good practice to avoid someone accessing them and causing us harm. This is particularly true if the keys are used for authentication or for accessing our own API that serves up user data. Using various techniques, we have removed the secrets from source control, kept them out of the project, encrypted them and applied protection to our encryption key.&lt;/p&gt;&lt;p&gt;On top of what has been discussed there are further practices that can be applied, some requiring more significant changes. It is best to evaluate the security needs of a particular application, based on what type of data it uses and the level of security a user would expect. Clearly a banking app will need to be much more security concious than a timer app, however, a good-level of security should be applied regardless to protect access to a user&#39;s data.&lt;/p&gt;
      </description>
      <pubDate>Sun, 16 Feb 2020 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/protecting-secrets-in-an-android-project/</guid>
    </item>    <item>
      <title>Enforcing type safety of IDs in Kotlin</title>
      <link>https://www.lordcodes.com/articles/enforcing-type-safety-of-ids-in-kotlin/</link>
      <description>
          &lt;p&gt;For codebases with many different entities, most of us will at some point have hit a bug due to the wrong ID being assigned to a property or passed to a function. Why don&#39;t we use the type system to give all of our IDs their own type and ensure this never happens again.&lt;/p&gt;&lt;p&gt;It is very common for objects to need a form of identifier or ID, frequently the reason being to refer to entities when communicating with a remote API or a database. We can easily implement this by giving our classes an ID property with an appropriate type, such as &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;UUID&lt;/code&gt; or &lt;code&gt;Long&lt;/code&gt;. An issue here is that imagine &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Team&lt;/code&gt; both have a &lt;code&gt;String&lt;/code&gt; ID, it would be perfectly possible to pass a &lt;code&gt;User&lt;/code&gt; ID to a function when we were meant to provide a &lt;code&gt;Team&lt;/code&gt; ID instead.&lt;/p&gt;&lt;p&gt;Let&#39;s explore the idea of enforcing type safety by giving our IDs their own types.&lt;/p&gt;&lt;h2 id=&quot;general-types&quot; tabindex=&quot;-1&quot;&gt;General types&lt;/h2&gt;&lt;p&gt;One option for our IDs is to use the &lt;code&gt;String&lt;/code&gt; type, especially if they are in an unexpected format. Another common type of ID is a &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc4122.txt&quot;&gt;UUID&lt;/a&gt;, an implementation of which is provided by the Java standard library. &lt;code&gt;UUID&lt;/code&gt; is designed for storing IDs and is a 128-bit value, which can be easily converted to and from a String.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Team&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UUID&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; size&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Int&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TeamMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;tiny-type&quot; tabindex=&quot;-1&quot;&gt;Tiny type&lt;/h2&gt;&lt;p&gt;Rather than relying on the general types, we can easily create a dedicated one.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; rawValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UUID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we require different raw types, we can either create extra ID types that contain different raw types or use a single one with a generic type parameter. Using a generic version allows us to have properties or function arguments that require a particular type of ID.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; Identifier&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RawT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; rawValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RawT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can add helpful extensions to &lt;code&gt;Identifier&lt;/code&gt; for use with common raw types, such as pulling out the raw &lt;code&gt;String&lt;/code&gt; value:&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; Identifier&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;UUID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uuidString&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String
    &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rawValue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;ensuring-the-correct-type&quot; tabindex=&quot;-1&quot;&gt;Ensuring the correct type&lt;/h2&gt;&lt;p&gt;There are some issues that can appear when using these general types internally. Say &lt;code&gt;Team&lt;/code&gt; has a &lt;code&gt;UUID&lt;/code&gt; ID and &lt;code&gt;Member&lt;/code&gt; has a &lt;code&gt;String&lt;/code&gt; ID:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Every &lt;code&gt;Team&lt;/code&gt; ID is a &lt;code&gt;UUID&lt;/code&gt;, but not every &lt;code&gt;UUID&lt;/code&gt; refers to a valid &lt;code&gt;Team&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;A &lt;code&gt;Member&lt;/code&gt; ID could have the same value as the raw &lt;code&gt;String&lt;/code&gt; backing a &lt;code&gt;Team&lt;/code&gt; ID, even though they refer to different entities.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Mixing and matching two different IDs that use the same raw type is perfectly valid and not prevented by the compiler. We can do better than this!&lt;/p&gt;&lt;p&gt;By adding a second generic type parameter to our &lt;code&gt;Identifier&lt;/code&gt; we can limit its use for a particular entity.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; Identifier&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;EntityT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; RawT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; rawValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RawT
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Identifier&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Room&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UUID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Meeting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Identifier&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Meeting&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UUID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bookMeeting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Identifier&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Meeting&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UUID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ❌ Compile error: Type mismatch.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;bookMeeting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;room&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Due to &lt;code&gt;EntityT&lt;/code&gt; not actually being used within &lt;code&gt;Identifier&lt;/code&gt; we will likely get a warning about it being unused, which can be ignored using &lt;code&gt;@Suppress(&amp;quot;unused&amp;quot;)&lt;/code&gt;.&lt;/p&gt;&lt;h2 id=&quot;type-aliases&quot; tabindex=&quot;-1&quot;&gt;Type aliases&lt;/h2&gt;&lt;p&gt;When our codebase has a variety of entities, the number of IDs will grow and we are likely to get fed up with typing out the &lt;code&gt;Identifier&lt;/code&gt; signature. We can rely on type aliases to simplify this task. A nice organisation tip is to store these alongside the entity they identify, making them easy to find.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Team.kt&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typealias&lt;/span&gt; TeamId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Identifier&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Team&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UUID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Team&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TeamId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Specifying IDs in properties and functions is now so much simpler.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Team&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;inviteMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MemberId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ❌ Compile error: Type mismatch.&lt;/span&gt;
team&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;inviteMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;team&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ✅ Compiles.&lt;/span&gt;
team&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;inviteMember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;member&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;alternatives&quot; tabindex=&quot;-1&quot;&gt;Alternatives&lt;/h2&gt;&lt;p&gt;If we wanted to avoid the generic type arguments, we could rely on the brevity of Kotlin data classes and simply have a separate tiny type for each ID.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MessageId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; raw&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UUID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ChatId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; raw&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PersonId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; raw&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Long&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The advantage is they are significantly simpler due to being just basic data classes, they could even be &lt;a href=&quot;https://kotlinlang.org/docs/reference/inline-classes.html&quot;&gt;inline classes&lt;/a&gt;. A possible downside is that with &lt;code&gt;Identifier&lt;/code&gt; we can write code that automatically converts &lt;code&gt;Identifier&lt;/code&gt; to other types for tasks such as storing in a &lt;code&gt;Bundle&lt;/code&gt; to pass to an &lt;code&gt;Activity&lt;/code&gt; or to a format &lt;code&gt;Room&lt;/code&gt; can store in a SQLite database. We will have to weigh up the pros and cons of each approach and decide what is best for our particular situation.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;By using a type that enforces type safety of our entity IDs, we can make our model code safer to work on and avoid bugs due to an incorrect ID being used. Our code will also be more readable as when we see an ID we will know which entity it refers to. There may even be ways to extend this solution to make it even more powerful!&lt;/p&gt;
      </description>
      <pubDate>Sun, 09 Feb 2020 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/enforcing-type-safety-of-ids-in-kotlin/</guid>
    </item>    <item>
      <title>The power of sealed classes in Kotlin</title>
      <link>https://www.lordcodes.com/articles/the-power-of-sealed-classes-in-kotlin/</link>
      <description>
          &lt;p&gt;Wouldn&#39;t it be great if you could represent a single type that can come in different forms, each able to be constant or carry their own data? If programming in Kotlin, we are in luck as that is exactly what a sealed class is perfect for!&lt;/p&gt;&lt;p&gt;Enums or enumerated types have existed in many different programming languages for years and allows us to represent a type whose value is taken from a limited set of values. Kotlin takes this concept and evolves into something much more powerful, known as &lt;a href=&quot;https://kotlinlang.org/docs/reference/sealed-classes.html&quot;&gt;sealed classes&lt;/a&gt;. They are a really useful addition to the language, enabling powerful use cases and can help us build some really nice APIs. Let&#39;s have a look at how sealed classes can be used, their benefits and some example situations in which they can be the perfect tool for the job.&lt;/p&gt;&lt;h2 id=&quot;how&quot; tabindex=&quot;-1&quot;&gt;How&lt;/h2&gt;&lt;p&gt;Both enums and sealed classes allow us to represent a type that can be one value from a set of possibilities. An enum consists of a set of constant values and the instance is assigned one of these constants. Sealed classes instead rely on a set of sub-classes, allowing us to have multiple instances of each sub-class and for them to have their own state.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Sealed class sub-classes can carry their own state&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Let&#39;s say we have an &lt;code&gt;AuthenticationState&lt;/code&gt; that keeps track of which state a user&#39;s account is in within our app. The user can be: signed in with a user identifier, signed out with some credentials stored or fully signed out.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; AuthState &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SignedIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; userGuid&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UUID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AuthState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;StoredCredentials&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; credentials&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Credentials&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AuthState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; SignedOut &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AuthState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By using a sealed class, a property of type &lt;code&gt;AuthenticationState&lt;/code&gt; has to have one of the sub-classes assigned to it. We can use a data class to give the sub-class its own properties or an object and make it constant.&lt;/p&gt;&lt;p&gt;Unlike with an enum, the sub-classes do not need to be kept in the body of the sealed class, only within the same file.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// AuthState.kt&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; AuthState
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SignedIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; userGuid&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UUID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AuthState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;StoredCredentials&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; credentials&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Credentials&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AuthState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; SignedOut &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AuthState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The way we choose to structure our sealed classes affects how they are referenced, the above examples resulting in &lt;code&gt;AuthState.SignedOut&lt;/code&gt; or &lt;code&gt;SignedOut&lt;/code&gt;. We can therefore place the sub-classes within the sealed class to create a namespace for our type.&lt;/p&gt;&lt;h2 id=&quot;when&quot; tabindex=&quot;-1&quot;&gt;When&lt;/h2&gt;&lt;p&gt;One of the situations sealed classes really stand out is within a &lt;code&gt;when&lt;/code&gt; expression. Using &lt;code&gt;when&lt;/code&gt; as an expression, assigning or returning the result, allows the compiler to determine if all possible cases have been handled, without needing an &lt;code&gt;else&lt;/code&gt; branch.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onAuthStateChanged&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; AuthState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SignedIn &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;showSignedIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userGuid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; AuthState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StoredCredentials &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;showSignedIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;credentials&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    AuthState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SignedOut &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;showSignedOut&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;The compiler can determine if all cases have been handled&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;By using sealed classes within our APIs we can make it really easy for consumers to handle all of the possible states. When used within our own code, if we add an extra sub-class then any &lt;code&gt;when&lt;/code&gt; statements used as an expression have to handle it.&lt;/p&gt;&lt;h2 id=&quot;view-state&quot; tabindex=&quot;-1&quot;&gt;View state&lt;/h2&gt;&lt;p&gt;In Android apps (or other GUI applications), we need a way to connect the logic that controls our UI to the views themselves. One part of this process may involve modelling the state of the view, such as if it is loading, showing an error or showing data.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; ViewState
&lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; LoadingState &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ViewState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PresentingState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; viewData&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ContactsViewData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ViewState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ErrorState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ViewState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Imagine we are developing a screen that displays a list of contacts loaded from a local database. Our view layer will receive the &lt;code&gt;ViewState&lt;/code&gt; and can then render the correct views based on which sub-class of the sealed class is received.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;renderViewState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viewState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ViewState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viewState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  LoadingState &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;showLoadingViews&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; PresentingState &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;showPresentingViews&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viewState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;viewData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; ErrorState &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;showErrorViews&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viewState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using a sealed class allows us to update our views for all the possible view states, along with each state carrying a different set of data:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;LoadingState&lt;/code&gt; can just be an &lt;code&gt;object&lt;/code&gt; with no data&lt;/li&gt;&lt;li&gt;&lt;code&gt;PresentingState&lt;/code&gt; brings with it &lt;code&gt;ContactsViewData&lt;/code&gt; to render the contacts&lt;/li&gt;&lt;li&gt;&lt;code&gt;ErrorState&lt;/code&gt; contains an error message to be shown&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Without a sealed class, we would need a class that contains all of the data as nullable properties and an enum to represent which state it was in.&lt;/p&gt;&lt;h2 id=&quot;analytics-events&quot; tabindex=&quot;-1&quot;&gt;Analytics events&lt;/h2&gt;&lt;p&gt;We will often need to work out how people are using our apps or verify the effectiveness of certain actions through the use of analytics. This usually boils down to firing off events after specific actions have been taken within the app. These analytics events will be reported in the same way, but may have different properties attached to them, this is a perfect candidate for a sealed class. Code that needs to handle the event can do this easily using a &lt;code&gt;when&lt;/code&gt; expression, for example, mapping each event to its map of properties.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; AnalyticsEvent &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; AccountCreated &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MessageSent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; conversation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Conversation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ProfileOpened&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; participant&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Participant&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AnalyticsEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Map&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Parameter&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        AccountCreated &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; MessageSent &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            Parameter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PARTICIPANT_COUNT &lt;span class=&quot;token keyword&quot;&gt;to&lt;/span&gt;
                conversation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;participants&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            Parameter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IS_ARCHIVED &lt;span class=&quot;token keyword&quot;&gt;to&lt;/span&gt;
                conversation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isArchived&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; ProfileOpened &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            Parameter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;HAS_ACCOUNT &lt;span class=&quot;token keyword&quot;&gt;to&lt;/span&gt;
                participant&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hasCreatedAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; Parameter &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        HAS_ACCOUNT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        IS_ARCHIVED&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        PARTICIPANT_COUNT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We could instead model an analytics event as a simple data class with a name and map of properties. An issue with this approach is it can spread the event names, property names and creation of events all over the codebase. The advantage of the sealed class approach is that we can keep the definition of all our events in one place, ensuring they are correct and that they report the correct properties. It is really great that sealed classes allow us the flexibility to have an &lt;code&gt;AnalyticsEvent&lt;/code&gt; type that can be passed around, even though it can come in many different forms.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Sealed classes are a really powerful feature of Kotlin, allowing the flexibility to model a single type that can come in a finite set of different forms. We have only explored a few of the use cases for them, I am sure you will find many more in your codebase!&lt;/p&gt;
      </description>
      <pubDate>Sun, 02 Feb 2020 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/the-power-of-sealed-classes-in-kotlin/</guid>
    </item>    <item>
      <title>Using Kotlin to bind Android views</title>
      <link>https://www.lordcodes.com/articles/using-kotlin-to-bind-android-views/</link>
      <description>
          &lt;p&gt;When working in the UI layer of an Android app, it won&#39;t be long before we need to perform an operation upon one of our views. In order to do this, we first need to retrieve it via &lt;code&gt;findViewById&lt;/code&gt;. Although using the API can seem simple, it does introduce a block of boilerplate to our Activities. On top of this the code to bind all the views usually ends up in &lt;code&gt;onCreate&lt;/code&gt;, completely separate from the view properties themselves.&lt;/p&gt;&lt;p&gt;Now that Kotlin has entered the scene with new features we didn&#39;t previously have access to it seems like the perfect time to look for a new way of doing things. We will explore how some different approaches, including lazy initialisation and Kotlin Android Extensions, can be used to solve this problem.&lt;/p&gt;&lt;h2 id=&quot;the-situation-in-java&quot; tabindex=&quot;-1&quot;&gt;The situation in Java&lt;/h2&gt;&lt;p&gt;To set the scene and to demonstrate how Kotlin can help we first need to look at how these tasks are achieved in Java. To bind views to a field, we would use &lt;code&gt;findViewById&lt;/code&gt;, historically casting the resulting view to the correct subclass. For an activity, the views would commonly be bound within &lt;code&gt;onCreate&lt;/code&gt;, however, this may be elsewhere if views are retrieved at another time.&lt;/p&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PlanningActivity&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppCompatActivity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextView&lt;/span&gt; planningText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageView&lt;/span&gt; appIcon&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onCreate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Bundle&lt;/span&gt; savedInstanceState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;onCreate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;savedInstanceState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;setContentView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layout&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activity_planning&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Before: Needed to cast&lt;/span&gt;
        planningText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;TextView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findViewById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;planningText&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Now: No longer need to&lt;/span&gt;
        appIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findViewById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appIcon&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        planningText&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The example here is very simple, containing only two views, whereas in reality many different views may need to be accessed. To avoid this repetitive boilerplate &lt;a href=&quot;https://github.com/JakeWharton/butterknife&quot;&gt;ButterKnife&lt;/a&gt; was created, which uses annotation processing to aid the binding of views.&lt;/p&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PlanningActivity&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppCompatActivity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@BindView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;planningText&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextView&lt;/span&gt; planningText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@BindView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appIcon&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageView&lt;/span&gt; appIcon&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onCreate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Bundle&lt;/span&gt; savedInstanceState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;onCreate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;savedInstanceState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;setContentView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layout&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activity_planning&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;ButterKnife&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        planningText&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;lazy-in-kotlin&quot; tabindex=&quot;-1&quot;&gt;Lazy in Kotlin&lt;/h2&gt;&lt;p&gt;The Kotlin programming language has many new features and so it feels natural that it may offer a better solution to what we were using before. A new concept in the language is that of &lt;a href=&quot;https://kotlinlang.org/docs/reference/delegated-properties.html&quot;&gt;delegated properties&lt;/a&gt;, specifically the &lt;code&gt;lazy&lt;/code&gt; delegated property. The way it works is that when the property is first accessed it will be initialized via the provided function and on future accesses the value will just be returned. This sounds perfect for binding views as the first access can call &lt;code&gt;findViewById&lt;/code&gt; and then subsequent calls can just provide the stored view.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; planningText &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; lazy &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    findViewById&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;TextView&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;planningText&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;A lazy delegated property is initialised on first access&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;To avoid typing all of this each time we want to bind a view, an extension function on &lt;code&gt;Activity&lt;/code&gt; can be created. We can also optimise performance slightly by disabling thread safety, due to the fact that the views will only be accessed from the main UI thread.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ViewT &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; View&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Activity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bindView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@IdRes&lt;/span&gt; idRes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Int&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Lazy&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ViewT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LazyThreadSafetyMode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NONE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        findViewById&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ViewT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;idRes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; PlanningActivity &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AppCompatActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; planningText &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; bindView&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;TextView&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;planningText&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// or&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; planningText&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TextView &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bindView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;planningText&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We now have a succinct and clear call site, with full control over the view binding and no generated code required. As &lt;code&gt;bindView&lt;/code&gt; is essentially a wrapper around &lt;code&gt;findViewById&lt;/code&gt; it can be applied elsewhere in the codebase, beyond just in &lt;code&gt;Activity&lt;/code&gt;.&lt;/p&gt;&lt;h2 id=&quot;lazy-elsewhere&quot; tabindex=&quot;-1&quot;&gt;Lazy elsewhere&lt;/h2&gt;&lt;p&gt;Applying to views, such as in a &lt;code&gt;RecyclerView.ViewHolder&lt;/code&gt; is as simple as creating a similar extension function to give us access to the same API we had within Activities.&lt;/p&gt;&lt;p&gt;Where our technique encounters some issues is when used within a &lt;code&gt;Fragment&lt;/code&gt; due to differences in their lifecycle. Without alterations the lazy property can refer to an old view instance after the &lt;code&gt;Fragment&lt;/code&gt; view has been recreated. We can either avoid lazy view binding in Fragments or put together a solution using the Lifecycle Architecture Component. By creating our own version of &lt;code&gt;Lazy&lt;/code&gt; we can reset the stored value in &lt;code&gt;onDestroyView&lt;/code&gt;, causing the next access to call &lt;code&gt;findViewById&lt;/code&gt; again. An example implementation demonstrating this idea can be &lt;a href=&quot;https://github.com/lordcodes/lordcodes-samples/blob/master/android/using-lazy-in-kotlin-to-bind-android-views/app/src/main/kotlin/com/lordcodes/lazyviewbindingarticle/lazyfragment/FragmentExt.kt&quot;&gt;found within the sample code&lt;/a&gt; for the article.&lt;/p&gt;&lt;h2 id=&quot;synthetic-properties&quot; tabindex=&quot;-1&quot;&gt;Synthetic properties&lt;/h2&gt;&lt;p&gt;As an alternative to implementing our own solution, especially if the situation with Fragments makes the lazy binding approach undesirable, we can use the &lt;a href=&quot;https://kotlinlang.org/docs/tutorials/android-plugin.html&quot;&gt;Kotlin Android Extensions&lt;/a&gt;. The plugin automatically generates properties that match the IDs of the views in our layout file. Views no longer need to be stored manually as properties, as they are instead accessed via synthetic properties generated by the plugin.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Automatically generated properties that bind to our views&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;We first need to apply the plugin within our Gradle configuration.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-gradle&quot;&gt;&lt;code class=&quot;language-gradle&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;apply&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;plugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;kotlin-android-extensions&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;plugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;kotlin-android-extensions&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once applied the plugin will generate synthetic properties for us to access views that are specified within our layout XML files, with names matching the IDs. To access the properties we need to add an import statement for each layout file. It is recommended to use the star syntax for the import, with Android Studio already having this specified within the default code style settings. The IDE should also add the import automatically when you try to reference one of the properties.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; kotlinx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;synthetic&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activity_planning&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; PlanningActivity &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AppCompatActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onCreate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;savedInstanceState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Bundle&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;onCreate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;savedInstanceState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;setContentView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layout&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activity_planning&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        planningText&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The plugin comes with other features such as applying to other custom containers and customising the view caching. Any features that are still considered experimental can be enabled within our Gradle configuration. Please find all the details of the other features on the &lt;a href=&quot;https://kotlinlang.org/docs/tutorials/android-plugin.html&quot;&gt;plugin website&lt;/a&gt;.&lt;/p&gt;&lt;pre class=&quot;language-gradle&quot;&gt;&lt;code class=&quot;language-gradle&quot;&gt;androidExtensions &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  experimental &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using Kotlin Android Extensions is a very clean approach, requiring practically no extra code. To previous users of ButterKnife it feels like an evolution to that approach. As with any potential solution it is best to try it out, see how it works and whether it fits with all the use cases a particular project has.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;When this article was originally written I recommended the lazy property approach due to us being able to strike a great balance between brevity, avoidance of boilerplate and reducing reliance on generated code. Since this time I have found that my preferred solution has shifted towards the Kotlin Android Extensions plugin due to its simplicity and not having to worry if there will be issues with lazy binding in situations such as that of Fragments.&lt;/p&gt;
      </description>
      <pubDate>Wed, 30 Jan 2019 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/using-kotlin-to-bind-android-views/</guid>
    </item>    <item>
      <title>Android signing keystore details from Gradle properties</title>
      <link>https://www.lordcodes.com/articles/android-signing-using-gradle-properties/</link>
      <description>
          &lt;p&gt;We may want to keep our Android project keystore details out of our source code and Git by passing them in. Aided by a handy function, these can be referenced from Gradle in Groovy or Kotlin.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gradle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Project

&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;propertyOrEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

android &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  signingConfigs &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;upload&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      storeFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;upload.keystore&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      storePassword &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;propertyOrEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;UPLOAD_STORE_PASSWORD&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      keyAlias &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;keyname&quot;&lt;/span&gt;&lt;/span&gt;
      keyPassword &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;propertyOrEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;UPLOAD_KEY_PASSWORD&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
      </description>
      <pubDate>Sun, 27 Jan 2019 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/android-signing-using-gradle-properties/</guid>
    </item>    <item>
      <title>Adding Continuous Integration to your Android project</title>
      <link>https://www.lordcodes.com/articles/adding-continuous-integration-android/</link>
      <description>
          &lt;p&gt;When working on a software project, particularly in a team, a common workflow involves branching from the main branch, often master or develop. The created branch is where changes for a particular feature or issue are applied. One way of managing this branch would involve committing all work for a large feature to this branch and then merging it back once it has been completed. This means the branch lives for a relatively long time and we will likely find the integration process to be a painful process.&lt;/p&gt;&lt;p&gt;Continuous Integration, commonly referred to as CI, is a popular development practice that instead involves integrating changes back into the main branch regularly. By integrating regularly the aim is that the cost of doing so will go down and errors will be detected more quickly. An important part of this process is that before changes are merged, the code is automatically built and tested. By testing before the merge instead of afterwards, integration issues are visible earlier and issues can hopefully be fixed more easily.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/LGKkzI87Wg-1000.webp 1000w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/LGKkzI87Wg-1000.jpeg&quot; alt=&quot;Continuous Integration diagram&quot; width=&quot;1000&quot; height=&quot;440&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Many people will agree that CI provides many benefits in a team environment, including in-house teams and open source projects with many different contributors. What is spoken about less often are the benefits of using CI in a solo environment. By having CI building and testing our code before it is merged, we can integrate code more safely and monitor it over time.&lt;/p&gt;&lt;h2 id=&quot;available-solutions&quot; tabindex=&quot;-1&quot;&gt;Available solutions&lt;/h2&gt;&lt;p&gt;In order to build and test code automatically, it is a good idea to have the process running on a CI server of some kind. This server monitors the codebase for changes, such as via a Pull Request using web-hooks, and then triggers the test suite to be executed. By ensuring the CI server is separate to the development machines verifies that it builds correctly in a clean and consistent environment.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;A pull request can automatically trigger a test run&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;When it comes to setting up and running a CI server, there are a huge number of services to choose from. We will have a look at a few that work differently to give an idea of what is available.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://circleci.com/&quot;&gt;&lt;strong&gt;Circle CI&lt;/strong&gt;&lt;/a&gt; is a cloud-based service that uses either Linux or MacOS virtual machines as the build environment. For Android, Linux is the best option due to the pricing being much more favourable with a free tier. Configuring the build jobs involves a YAML file within the project, resulting in a process that is very customisable.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/Lsr2yAgao5-300.webp 300w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/Lsr2yAgao5-300.jpeg&quot; alt=&quot;Circle CI logo&quot; width=&quot;300&quot; height=&quot;246&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://bitrise.io&quot;&gt;&lt;strong&gt;Bitrise&lt;/strong&gt;&lt;/a&gt; is similar to Circle CI in that it is a cloud-based service, however, it is tailored to the individual needs of mobile development. This means it has many mobile specific integrations, including deploying to Google Play alongside services such as TestFairy and Firebase Test Lab. As with Circle CI there is a free tier, although it is fairly limited in terms of build minutes allowed. Configuring the build jobs can be done either via a YAML file in the project or using the workflow editor directly within the web UI, giving an increased level of flexibility.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/DeEkOx5Fmj-430.webp 430w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/DeEkOx5Fmj-430.jpeg&quot; alt=&quot;Bitrise logo&quot; width=&quot;430&quot; height=&quot;164&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.jenkins.io&quot;&gt;&lt;strong&gt;Jenkins&lt;/strong&gt;&lt;/a&gt; is the leading self-hosted automation server that we install, configure and maintain ourselves on our own hardware or cloud infrastructure. Jenkins is perfect for people who want to maintain the full CI set up themselves. It is incredibly customisable, where we can essentially make it do whatever we want, boasting a huge number of plugins and integrations from the community. It does come at the cost of doing all this, where the other cloud-based solutions are managed for you.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/dc0yTPuWkn-490.webp 490w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/dc0yTPuWkn-490.jpeg&quot; alt=&quot;Jenkins logo&quot; width=&quot;490&quot; height=&quot;185&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;There are many other CI solutions that haven&#39;t been mentioned here including: &lt;a href=&quot;https://www.travis-ci.com&quot;&gt;Travis CI&lt;/a&gt;, &lt;a href=&quot;https://codemagic.io/start/&quot;&gt;CodeMagic&lt;/a&gt;, &lt;a href=&quot;https://about.gitlab.com/solutions/continuous-integration/&quot;&gt;GitLab CI&lt;/a&gt;, &lt;a href=&quot;https://www.jetbrains.com/teamcity/&quot;&gt;TeamCity&lt;/a&gt; and &lt;a href=&quot;https://www.atlassian.com/software/bitbucket/features/pipelines&quot;&gt;Bitbucket Pipelines&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The best solution isn&#39;t the same for everyone. The best solution depends on individual requirements, the features we want and also personal preference. To explore the process of setting up CI, we will look at getting a simple workflow running in both Circle CI and Bitrise via the web UI, for comparison.&lt;/p&gt;&lt;h2 id=&quot;circle-ci&quot; tabindex=&quot;-1&quot;&gt;Circle CI&lt;/h2&gt;&lt;p&gt;Once our Circle CI account has been created and integrated with our source control, such as GitHub or Bitbucket, we can start creating our CI config. For Circle CI, this needs to be a YAML file at &lt;code&gt;.circleci/config.yml&lt;/code&gt;.&lt;/p&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.0&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;working_directory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ~/workspace
    &lt;span class=&quot;token key atrule&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; circleci/android&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;28&lt;/span&gt;

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; checkout

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Run tests
          &lt;span class=&quot;token key atrule&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./gradlew lintDebug testDebugUnitTest

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;store_artifacts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; app/build/reports
          &lt;span class=&quot;token key atrule&quot;&gt;destination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; reports
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;store_test_results&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; app/build/test&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;results&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;We start off by requesting Circle CI 2.0.&lt;/li&gt;&lt;li&gt;We can next set up our jobs, which in this simple example consist of a single job that runs Android Lint and our unit tests.&lt;/li&gt;&lt;li&gt;The first thing our job needs to do is configure the working directory and the image to use for our build environment. The working directory will be needed to do more advanced customisations such as sharing a workspace between steps in a workflow.&lt;/li&gt;&lt;li&gt;Within the build job definition, we can list the steps to take, starting with checking out the code, running our tests and archiving the test results.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This example only covers the very basics and there is much more we can do with our configuration. An example showing a more advanced workflow including caching and sharing the workspace between workflow steps &lt;a href=&quot;https://gist.github.com/lordcodes/65101116156a44b075ce2a126313b9c6&quot;&gt;can be found as a gist&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/PQfS5_G_cR-1000.webp 1000w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/PQfS5_G_cR-1000.jpeg&quot; alt=&quot;Circle CI workflow&quot; width=&quot;1000&quot; height=&quot;700&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=&quot;bitrise&quot; tabindex=&quot;-1&quot;&gt;Bitrise&lt;/h2&gt;&lt;p&gt;After creating our Bitrise account, we can add our app to Bitrise by following through the full set up wizard. Bitrise is specifically designed for mobile, the detailed wizard helping with pretty much all of the heavy lifting. Once complete and on the dashboard page for our project, the navigation banner should be visible, giving us access to all of the customisation we need.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/BKEuGXkWDY-1440.webp 1440w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/BKEuGXkWDY-1440.jpeg&quot; alt=&quot;Bitrise navigation banner&quot; width=&quot;1440&quot; height=&quot;120&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Entering into the &#39;workflow&#39; area, we will be able to fine tune the default generated workflow as well as add any extra workflows we will need. Each workflow can be &lt;a href=&quot;https://devcenter.bitrise.io/en/builds/starting-builds/triggering-builds-automatically.html&quot;&gt;triggered at different times&lt;/a&gt;, so we could have one that runs for pull requests and another for tagged commits as an example.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/ZMKfJyy0G0-1440.webp 1440w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/ZMKfJyy0G0-1440.jpeg&quot; alt=&quot;Bitrise workflow&quot; width=&quot;1440&quot; height=&quot;510&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;For our build we will need:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Activate SSH key&lt;/strong&gt; to set up SSH access to our source code.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Git clone repository&lt;/strong&gt; to retrieve our source code.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Install missing Android SDK components&lt;/strong&gt; to ensure the Android SDK is available and updated.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Gradle Runner&lt;/strong&gt; to run a Gradle task of our choice, where we should set the &#39;Gradle task to run&#39; to &lt;code&gt;lintDebug&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Gradle Unit Test&lt;/strong&gt; to run unit tests with Gradle, where we should set the &#39;Test task&#39; to &lt;code&gt;testDebugUnitTest&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Deploy to Bitrise.io&lt;/strong&gt; to deploy files and attach them to the Bitrise build page.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This covers a basic workflow that matches the one we created for Circle CI above. More advanced workflows can easily be put together using the &lt;a href=&quot;https://bitrise.io/integrations&quot;&gt;many steps available&lt;/a&gt;, which are open source and &lt;a href=&quot;https://github.com/bitrise-io/bitrise-steplib/tree/master/steps&quot;&gt;viewable on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Both Circle CI and Bitrise are very powerful and capable CI tools that apply well to Android development. Both solutions also work well for iOS development, allowing teams that develop for both platforms to use the same tool and subscription.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Circle CI&lt;/strong&gt; has a more generous free tier in terms of usage, is highly customisable and will be very familiar with those used to configuring CI with a YAML file. &lt;strong&gt;Bitrise&lt;/strong&gt; has more mobile specific plugins available out-of-the-box, allows configuration via the web UI and has a much more user-friendly interface.&lt;/p&gt;&lt;p&gt;It is important to find the right CI tool for the job by trying out the different options. When it comes to CI everyone will have a personal preference and this plays an important role in the decision of which one to use. It is even worth thinking about using CI for solo projects, although there is a set up and maintenance cost, it is still very valuable knowing that the project builds and that all tests are passing.&lt;/p&gt;
      </description>
      <pubDate>Thu, 24 Jan 2019 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/adding-continuous-integration-android/</guid>
    </item>    <item>
      <title>Set up Kotlin source directory from Gradle Kotlin DSL</title>
      <link>https://www.lordcodes.com/articles/kotlin-source-directory-gradle-kotlin-dsl/</link>
      <description>
          &lt;p&gt;When converting Android Gradle files from Groovy to Kotlin, one thing that may not be clear is how to keep Kotlin sources within &lt;code&gt;src/main/kotlin&lt;/code&gt;. We simply need to get the source sets by name and call &lt;code&gt;java.srcDirs()&lt;/code&gt; as a function call. Works like a dream!&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;sourceSets &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getByName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;srcDirs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src/main/kotlin&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getByName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;srcDirs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src/test/kotlin&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getByName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;androidTest&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;srcDirs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src/androidTest/kotlin&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
      </description>
      <pubDate>Sun, 20 Jan 2019 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/kotlin-source-directory-gradle-kotlin-dsl/</guid>
    </item>    <item>
      <title>Testing on Android using JUnit 5</title>
      <link>https://www.lordcodes.com/articles/testing-on-android-using-junit-5/</link>
      <description>
          &lt;p&gt;JUnit 4 has always been the standard unit testing framework for Android development, however, a production version of JUnit 5 has been available for &lt;a href=&quot;https://github.com/junit-team/junit5/releases/tag/r5.0.0&quot;&gt;quite a while&lt;/a&gt;. JUnit 5 is the next generation of JUnit testing and has quite a new structure. From a user-perspective it offers a number of useful new features and various other benefits. Often Android developers are used to waiting a while for new things from the Java-world to be an option on Android. In the case of JUnit 5, with some changes to your Gradle dependencies, you can use it right now from your Java and Kotlin unit tests.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/FalfGKh-ji-700.webp 700w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/FalfGKh-ji-700.jpeg&quot; alt=&quot;JUnit 5 logo&quot; title=&quot;Testing on Android with JUnit 5&quot; width=&quot;700&quot; height=&quot;375&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;The architecture of JUnit 5 is quite a significant change from before, with the framework being split into three major components.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;JUnit Platform&lt;/strong&gt; is the underlying layer on which testing frameworks can run on the JVM and offers up the API for different test engines.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;JUnit Jupiter&lt;/strong&gt; defines how we write JUnit 5 tests and then contains an engine for running these tests on the platform.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;JUnit Vintage&lt;/strong&gt; gives us an engine for running our previous JUnit 4 tests. We don&#39;t need to worry about having to update all of our tests in one go, as we can use the vintage engine to run these and have both JUnit 4 and 5 tests within our project.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;As users of the testing framework, it&#39;s likely that the most interesting part is the new features we get access to. Nested tests allow us to put our tests into groups, increasing readability and allowing us to reduce repetition within test names. Parameterised tests are really powerful and can also reduce duplicating tests to give different inputs, the parameters can even be provided through a variety of mechanisms. Dynamic tests offer an API to generate tests on the fly using a test factory, rather than hard-coding each of the tests.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Parameterised tests run tests with different inputs&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The JUnit 5 extension model allows us to extend the test framework and is the evolution of concepts from JUnit 4 such as &lt;code&gt;@Rule&lt;/code&gt; and custom runners. The extension model will allow JUnit 5 to evolve with all developers and tool makers having the same public extension API. There are many more features beyond those listed here, all of which can be found in &lt;a href=&quot;https://junit.org/junit5/docs/current/user-guide/#writing-tests&quot;&gt;the user guide&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Now, let&#39;s get JUnit 5 running in our Android project.&lt;/p&gt;&lt;h2 id=&quot;configuring-gradle&quot; tabindex=&quot;-1&quot;&gt;Configuring Gradle&lt;/h2&gt;&lt;p&gt;Thanks to &lt;a href=&quot;https://github.com/mannodermaus&quot;&gt;Marcel Schnelle (mannodermaus)&lt;/a&gt; there is an easy-to-use &lt;a href=&quot;https://github.com/mannodermaus/android-junit5&quot;&gt;Gradle plugin&lt;/a&gt; that will configure all the testing tasks to use JUnit 5. The plugin has a few &lt;a href=&quot;https://github.com/mannodermaus/android-junit5/wiki/Getting-Started&quot;&gt;minimum requirements&lt;/a&gt; that our project needs to meet, at the time of writing this is the Android Gradle plugin 3.2.0+, Gradle 4.7+ and Java 8+.&lt;/p&gt;&lt;p&gt;We will start by adding the plugin to our root &lt;code&gt;build.gradle&lt;/code&gt; file using the latest version, which at time of writing is 1.3.2.0.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;buildscript &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    classpath &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;de.mannodermaus.gradle.plugins:android-junit5:1.3.2.0&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After a successful Gradle sync, we will be ready to apply the plugin to any Android modules we wish to use JUnit 5 in.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /app/build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;apply plugin&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;de.mannodermaus.android-junit5&#39;&lt;/span&gt;

dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  testImplementation &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.junit.jupiter:junit-jupiter-api:5.3.2&quot;&lt;/span&gt;&lt;/span&gt;
  testRuntimeOnly &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.junit.jupiter:junit-jupiter-engine:5.3.2&quot;&lt;/span&gt;&lt;/span&gt;
  testImplementation &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.junit.jupiter:junit-jupiter-params:5.3.2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If there are JUnit 4 tests in the project we are configuring, then we will also need to keep the JUnit 4 dependency and enable the JUnit vintage test engine mentioned above.&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;testImplementation &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;junit:junit:4.12&quot;&lt;/span&gt;&lt;/span&gt;
testRuntimeOnly &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.junit.vintage:junit-vintage-engine:5.3.2&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once the plugin and the Gradle dependencies have been configured, we can run tests in the same way as we were previously using the same Gradle tasks and run configurations in Android Studio.&lt;/p&gt;&lt;p&gt;If we need them, there are &lt;a href=&quot;https://github.com/mannodermaus/android-junit5/wiki/Configuration&quot;&gt;some options&lt;/a&gt; for configuring the test environment within Gradle. Our settings go in a &lt;code&gt;junitPlatform&lt;/code&gt; block within the existing &lt;code&gt;testOptions&lt;/code&gt;, where we may already be doing some configuration. The most common use-case would be for filtering which tests are executed. We could use the filters to divide our tests into unit and integration and then have them run for different variants, as an example.&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;android &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  testOptions &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    junitPlatform &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      filters &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        includePattern &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;^(tests_to_include_regex)$&quot;&lt;/span&gt;&lt;/span&gt;
        excludePattern &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;^(tests_to_exclude_regex)$&quot;&lt;/span&gt;&lt;/span&gt;

        includeTags &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slow&quot;&lt;/span&gt;&lt;/span&gt;
        excludeTags &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;integration&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      debugFilters &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        includeTags &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;integration&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For any more information on the plugin, all the setup and usage instructions can be found &lt;a href=&quot;https://github.com/mannodermaus/android-junit5&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;h3 id=&quot;jvm-tests-only&quot; tabindex=&quot;-1&quot;&gt;JVM tests only&lt;/h3&gt;&lt;p&gt;If our unit tests are only going to be ran on the JVM, no Robolectric or Android required, then we can get away without the Gradle plugin. To do this we can remove the plugin classpath entry from the root &lt;code&gt;build.gradle&lt;/code&gt; and the line where the plugin is applied within the app module &lt;code&gt;build.gradle&lt;/code&gt;. Instead we need to add some configuration to &lt;code&gt;testOptions&lt;/code&gt; to enable running with JUnit 5.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /app/build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;android &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  testOptions &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    unitTests&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;all &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;useJUnitPlatform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We lose the per-variant filters that were demonstrated above if we go down this route. However, for most Android projects that aren&#39;t using Robolectric this should definitely be sufficient.&lt;/p&gt;&lt;h2 id=&quot;writing-the-tests&quot; tabindex=&quot;-1&quot;&gt;Writing the tests&lt;/h2&gt;&lt;p&gt;Let&#39;s write some tests to explore the new features of JUnit 5 and how we should go about using it in our apps. We will be using &lt;a href=&quot;http://joel-costigliola.github.io/assertj/&quot;&gt;AssertJ&lt;/a&gt; for our assertions, mainly for readability within the samples. We will be testing a very simple repository that allows us to look up contacts using their IDs, starting with the JUnit 4 version.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;assertj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Assertions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;assertThat
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Test

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; ContactsRepositoryTest &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; repository &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ContactsRepository&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token annotation builtin&quot;&gt;@Test&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findContact_givenExistingId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; expectedContact &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Contact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Melanie&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; actualContact &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; repository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findContact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actualContact&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expectedContact&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Converting this test to JUnit 5 is as simple as changing the import for &lt;code&gt;@Test&lt;/code&gt;. Projects with many more tests, using more features of JUnit 4, may have more changes that are required. As mentioned above, we can start new tests in JUnit 5 and then either leave the JUnit 4 ones as is, or convert them gradually.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Test

&lt;span class=&quot;token comment&quot;&gt;// After&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Test&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;descriptive-test-names&quot; tabindex=&quot;-1&quot;&gt;Descriptive test names&lt;/h2&gt;&lt;p&gt;A common structure for tests is breaking them into &lt;strong&gt;given&lt;/strong&gt;, &lt;strong&gt;when&lt;/strong&gt; and &lt;strong&gt;then&lt;/strong&gt;.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;strong&gt;given&lt;/strong&gt; clause involves setting up the conditions for the test, such as mocking or configuring the component we are about to test.&lt;/li&gt;&lt;li&gt;Within the &lt;strong&gt;when&lt;/strong&gt; clause, we execute the behaviour we are looking to verify.&lt;/li&gt;&lt;li&gt;It is in the &lt;strong&gt;then&lt;/strong&gt; clause that we check the behaviour is working correctly with any assertions.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This structure is fairly clear within the body of the test function, however, in the naming of the function some issues may start to arise.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;givenContactsLoadedAndIdMatches_whenFindContact_thenContactReturned&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token annotation builtin&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;givenContactsNotLoadedAndIdMatches_whenFindContact_thenNoContactReturned&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Some approaches could be taken to reduce the length, such as using shorter wording in the given clauses and potentially removing the then clause from the name. This does result in losing some detail, which can be really useful in test names to quickly see in the test report what is going on and to demonstrate what a test is supposed to do. It is also much easier to read a descriptive sentence than the camel-case seen in function names.&lt;/p&gt;&lt;p&gt;JUnit 5 introduces the &lt;code&gt;@DisplayName&lt;/code&gt; annotation, which can be used to provide a descriptive name for the test report. The same result can be achieved in Kotlin through the use of back-ticks around the function name. The advantage of the &lt;code&gt;@DisplayName&lt;/code&gt; approach is that we keep the searchable and familiar function name, whereas the back-tick approach avoids the need to maintain both the function name and annotation.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@DisplayName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Given contacts are loaded but the ID is invalid, When we find a contact, Then no contact is returned.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findContact_givenExistingId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token annotation builtin&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;`Given contacts are loaded but ID invalid, When we find a contact, Then no contact returned`&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;structuring-tests&quot; tabindex=&quot;-1&quot;&gt;Structuring tests&lt;/h2&gt;&lt;p&gt;A common reason for test names growing in length is having multiple tests with the same starting condition. Beyond naming, a similar starting condition can cause test bodies to grow in length as well! To solve the issue, JUnit 5 introduces &lt;code&gt;@Nested&lt;/code&gt;, allowing you to group a set of tests into an inner class. The group can have a shared starting state and can also have a display name specified, reducing the length of individual test function names. The nested structure is shown within the test report, making it very readable.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@Nested&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@DisplayName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Given valid contact ID&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;inner&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; ValidContactId  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;

  &lt;span class=&quot;token annotation builtin&quot;&gt;@Test&lt;/span&gt;
  &lt;span class=&quot;token annotation builtin&quot;&gt;@DisplayName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;When find contact, then correct contact returned&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findContact_givenExistingId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; expectedContact &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Contact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Melanie&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; actualContact &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; repository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findContact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actualContact&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expectedContact&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After fleshing out the tests for this repository more, with a few tests in each group, we can peek at the test report to see how it all looks. 👀&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/wpj62nUvka-1024.webp 1024w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/wpj62nUvka-1024.jpeg&quot; alt=&quot;Android Studio test report&quot; title=&quot;Android Studio test report&quot; width=&quot;1024&quot; height=&quot;449&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;The code we have written is available &lt;a href=&quot;https://github.com/lordcodes/lordcodes-samples/tree/master/android/unit-testing-on-android-using-junit-5&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;instrumentation-tests&quot; tabindex=&quot;-1&quot;&gt;Instrumentation tests&lt;/h2&gt;&lt;p&gt;We have been discussing unit tests only and as we all know instrumentation tests, usually using &lt;a href=&quot;https://developer.android.com/training/testing/espresso/&quot;&gt;Espresso&lt;/a&gt;, are also very important. Currently, our Espresso tests will be using JUnit 4, which can be left as it was previously. This means using the JUnit 4 test runner, as opposed to adding the JUnit 5 vintage engine and using the new infrastructure.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Instrumentation tests using the JUnit 5 Gradle plugin are still considered experimental&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The Gradle plugin we used to introduce JUnit 5 on Android has support for instrumentation tests, which at the time of writing is considered experimental. From checking the GitHub issues page for the plugin, many people have had problems using JUnit 5 for their instrumentation test suite. When the situation changes this article will be updated with the current details of using it.&lt;/p&gt;&lt;p&gt;Since JUnit 5 is built upon Java 8, to use it we need a &lt;code&gt;minSdkVersion&lt;/code&gt; of 26 or above. Before we start freaking out, this can be achieved by running the tests with a product flavour that has the minimum SDK increased to this level.&lt;/p&gt;&lt;p&gt;To write and run our instrumentation tests using the JUnit 5 framework, we will need some Gradle configuration. A little bit more is required than for unit tests, due to needing to tell the system to to use the plugin&#39;s runner builder and ensuring tests running on the device work correctly.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /app/build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;android &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  defaultConfig &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    testInstrumentationRunner &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;android.support.test.runner.AndroidJUnitRunner&quot;&lt;/span&gt;&lt;/span&gt;
    testInstrumentationRunnerArgument &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;runnerBuilder&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;de.mannodermaus.junit5.AndroidJUnit5Builder&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  androidTestImplementation &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.junit.jupiter:junit-jupiter-api:5.3.2&quot;&lt;/span&gt;&lt;/span&gt;
  androidTestImplementation &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;de.mannodermaus.junit5:android-instrumentation-test:0.2.2&quot;&lt;/span&gt;&lt;/span&gt;

  androidTestRuntimeOnly &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.junit.jupiter:junit-jupiter-engine:5.3.2&quot;&lt;/span&gt;&lt;/span&gt;
  androidTestRuntimeOnly &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.junit.platform:junit-platform-runner:1.3.2&quot;&lt;/span&gt;&lt;/span&gt;
  androidTestRuntimeOnly &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;de.mannodermaus.junit5:android-instrumentation-test-runner:0.2.2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is noteworthy that instrumentation tests tend to have less need for JUnit 5, due to there being less tests and fewer variants of similar tests, in general. This will of course depend heavily from project to project though! To find out more, please check out the plugin&#39;s &lt;a href=&quot;https://github.com/mannodermaus/android-junit5#instrumentation-test-support&quot;&gt;GitHub page&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;We have only considered a few small aspects of writing JUnit 5 tests, as there is simply so much to look at. To find out more, there is a detailed &lt;a href=&quot;https://junit.org/junit5/docs/current/user-guide/#writing-tests&quot;&gt;user guide&lt;/a&gt; covering all parts of the framework and how to go about writing tests and customising the test process.&lt;/p&gt;&lt;p&gt;By using JUnit 5 in our Android app testing we are using the latest evolution of the JUnit framework. It gives us access to more features, helps us make tests as readable as possible, reduce duplication within our tests and extending the test framework has never been easier. Hopefully it will catch on more in the Android community and become the &amp;quot;standard&amp;quot; for Android development sooner rather than later.&lt;/p&gt;
      </description>
      <pubDate>Fri, 30 Nov 2018 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/testing-on-android-using-junit-5/</guid>
    </item>    <item>
      <title>Enable Java 8 compatibility for Kotlin sources</title>
      <link>https://www.lordcodes.com/articles/enable-java-8-compatibility-for-kotlin-sources/</link>
      <description>
          &lt;p&gt;Enabling Java 8 compatibility via the &lt;code&gt;compileOptions&lt;/code&gt; block only works for Java sources. To do the same for Kotlin you need to use &lt;code&gt;kotlinOptions&lt;/code&gt; on any KotlinCompile Gradle tasks. Interesting…&lt;/p&gt;&lt;p&gt;&lt;strong&gt;For Kotlin&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;tasks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;withType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jetbrains&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gradle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tasks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;KotlinCompile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    kotlinOptions &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        jvmTarget &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; JavaVersion&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VERSION_1_8
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;For Java&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;android &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  compileOptions &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    sourceCompatibility JavaVersion&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VERSION_1_8
    targetCompatibility JavaVersion&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VERSION_1_8
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
      </description>
      <pubDate>Tue, 27 Nov 2018 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/enable-java-8-compatibility-for-kotlin-sources/</guid>
    </item>    <item>
      <title>Manage Gradle dependencies using Kotlin code in buildSrc</title>
      <link>https://www.lordcodes.com/articles/gradle-dependencies-using-kotlin-in-buildsrc/</link>
      <description>
          &lt;p&gt;Using Kotlin to maintain our Gradle dependencies within the buildSrc directory can be really great.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Allows us to use a familiar syntax&lt;/li&gt;&lt;li&gt;Provides auto-complete within Groovy or Kotlin Gradle scripts&lt;/li&gt;&lt;li&gt;Can click through to a particular dependencies definition&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Sweet!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /buildSrc/src/main/java/com/myapp/Versions.kt&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;myapp

&lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; Versions &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; AndroidX &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; appCompat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1.0.2&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; kotlin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1.3.10&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;→ /buildSrc/src/main/java/com/myapp/Libs.kt&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;myapp

&lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; Libs &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; AndroidX &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; appCompat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;androidx.appcompat:appcompat:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AndroidX&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appCompat&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; kotlinStdlib &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.jetbrains.kotlin:kotlin-stdlib:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlin&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;→ /src/app/build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;myapp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Libs

dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  implementation Libs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlinStdlib
  implementation Libs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AndroidX&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appCompat
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
      </description>
      <pubDate>Tue, 27 Nov 2018 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/gradle-dependencies-using-kotlin-in-buildsrc/</guid>
    </item>    <item>
      <title>Manage your Gradle dependencies in Kotlin, even from Groovy scripts</title>
      <link>https://www.lordcodes.com/articles/gradle-dependencies-using-kotlin/</link>
      <description>
          &lt;p&gt;When defining the dependencies for a Gradle project, such as an Android app, there are situations that call for duplicated information. A common case is that libraries or plugins can often come with multiple dependencies, which are usually released together with matching versions. Maintaining these dependencies requires the version to be duplicated and then kept up-to-date as new versions are released.&lt;/p&gt;&lt;p&gt;Another case is that it is common to have a multi-module project, where we may want a dependency to be added to multiple modules. Similarly to the case with versions, the dependency definition would be duplicated for each module and then kept in-sync moving forward.&lt;/p&gt;&lt;p&gt;It is clear that in both cases we may want to define the dependencies in one place and then access this location from wherever the dependency definition is needed.&lt;/p&gt;&lt;h2 id=&quot;the-groovy-way&quot; tabindex=&quot;-1&quot;&gt;The Groovy way&lt;/h2&gt;&lt;p&gt;There is a mechanism for sharing your dependency configuration using Groovy, by adding some extra properties in our root &lt;code&gt;build.gradle&lt;/code&gt; file, similar to below.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;buildscript &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;versions &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;kotlin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;1.3.10&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;dagger&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;2.19&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

  ext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;deps &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;kotlin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;stdlib&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.jetbrains.kotlin:kotlin-stdlib:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlin&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;test&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.jetbrains.kotlin:kotlin-test-common:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlin&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;dagger&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;runtime&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.google.dagger:dagger:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;compiler&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.google.dagger:dagger-compiler:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;androidRuntime&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.google.dagger:dagger-android:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;androidCompiler&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.google.dagger:dagger-android-processor:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;→ /app/build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  implementation deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stdlib

  implementation deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime
  implementation deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;androidRuntime
  kapt deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compiler
  kapt deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;androidCompiler

  testImplementation deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sharing the configuration via the root &lt;code&gt;build.gradle&lt;/code&gt; achieves the goal of having a single location to maintain. Only needing to update dependency versions in a single file is a great time-saver as well. Unfortunately from practice, when using the Groovy Gradle DSL auto-complete is often missing or incomplete in this situation, making it awkward to use.&lt;/p&gt;&lt;p&gt;On top of this, &lt;a href=&quot;https://gradle.org/whats-new/gradle-5/&quot;&gt;Gradle 5.0&lt;/a&gt; is now available which includes the production-ready Kotlin Gradle DSL. When we convert the above solution to Kotlin it isn&#39;t as nice to use in Kotlin as it is in Groovy. The map syntax can be achieved using &lt;code&gt;mapOf&lt;/code&gt;, but reading the data to pass to &lt;code&gt;implementation&lt;/code&gt; requires some casting to fit with the statically typed language.&lt;/p&gt;&lt;h2 id=&quot;kotlin-to-the-rescue&quot; tabindex=&quot;-1&quot;&gt;Kotlin to the rescue&lt;/h2&gt;&lt;p&gt;As many developers have found with their main app source code, Kotlin can help with defining our dependency configurations as well, from both Groovy and Kotlin Gradle scripts.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/yxUelyoALR-1400.webp 1400w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/yxUelyoALR-1400.jpeg&quot; alt=&quot;Kotlin and Gradle logos&quot; title=&quot;Kotlin and Gradle - a match made in heaven?&quot; width=&quot;1400&quot; height=&quot;613&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;When ran, Gradle will check for a &lt;code&gt;buildSrc&lt;/code&gt; directory in the root of the project, placing any code that is found into the classpath of our build. This is really handy and allows us to put Kotlin code into &lt;code&gt;buildSrc&lt;/code&gt; and then reference it from our Gradle scripts. To get started we just need a little bit of structure.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /buildSrc/build.gradle.kts&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;plugins {
  `kotlin-dsl`
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Kotlin DSL plugin needs to be specified for &lt;code&gt;buildSrc&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /buildSrc/src/main/kotlin/Versions.kt&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Our source files need to be placed within the standard sources directory structure. To use inner objects, for now we need to include the sources within a package, e.g. &#39;com.ourapp&#39;.&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; Versions &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; dagger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2.21&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; ktlint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0.29.0&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; kotlin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1.3.11&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;→ /buildSrc/src/main/kotlin/Dependencies.kt&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; Plugins &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; kotlin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.jetbrains.kotlin:kotlin-gradle-plugin:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlin&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; ktlint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.github.shyiko:ktlint:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ktlint&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; Libs &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; kotlinStdlib &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;org.jetbrains.kotlin:kotlin-stdlib:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlin&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; daggerRuntime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.google.dagger:dagger:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; daggerCompiler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.google.dagger:dagger-compiler:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; daggerAndroidRuntime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.google.dagger:dagger-android:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; daggerAndroidCompiler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;com.google.dagger:dagger-android-processor:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;Versions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dagger&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once Gradle has been synced, we can now reference our dependencies within our Gradle scripts. This is pretty much the same as we used with the Groovy extra properties solution above.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;→ /app/build.gradle&lt;/strong&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  implementation Libs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;kotlinStdlib

  implementation Libs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;daggerRuntime
  implementation Libs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;daggerAndroidRuntime
  kapt Libs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;daggerCompiler
  kapt Libs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;daggerAndroidCompiler

  ktlint Plugins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ktlint
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using &lt;code&gt;buildSrc&lt;/code&gt; and Kotlin sources achieves the goal of having a single location to maintain and we can even reduce it to a single Kotlin source file if it makes sense to. The solution can be used in the same way from both Groovy and Kotlin Gradle DSL without being altered, which frees us up to change our Gradle scripts to Kotlin if we want to.&lt;/p&gt;&lt;p&gt;The best thing about defining dependencies in this way is that we get access to effective auto-complete and being able to click through to where a dependency is defined from our Gradle scripts, super useful.&lt;/p&gt;&lt;p&gt;A good tool to look into is &lt;a href=&quot;https://github.com/ben-manes/gradle-versions-plugin&quot;&gt;Ben Manes&#39; Gradle Versions Plugin&lt;/a&gt;, which will inform us of any dependencies with new versions. Once we have the latest versions, we can simply update them in &lt;code&gt;Versions.kt&lt;/code&gt;.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Naturally, for the reasons given I prefer to use the &lt;code&gt;buildSrc&lt;/code&gt; and Kotlin source approach in my Android projects. It is really nice to use with both Groovy Gradle scripts and those written using the Gradle Kotlin DSL.&lt;/p&gt;
      </description>
      <pubDate>Fri, 23 Nov 2018 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/gradle-dependencies-using-kotlin/</guid>
    </item>    <item>
      <title>Welcome to Android Studio 3.0</title>
      <link>https://www.lordcodes.com/articles/welcome-to-android-studio-3-0/</link>
      <description>
          &lt;p&gt;After a long wait, Android Studio 3.0 has finally been released to the stable channel. This means everyone should be updating their IDE to the latest and greatest version. There are so many new features and improvements it is just a no brainer! I will go over the new features later on, but for now I will discuss the process of updating and cover the breaking changes in the new Gradle plugin.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/UpsHHDZZCH-1200.webp 1200w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/UpsHHDZZCH-1200.jpeg&quot; alt=&quot;Android Studio 3.0 with logo&quot; title=&quot;Android Studio 3.0 - It&#39;s arrived!&quot; width=&quot;1200&quot; height=&quot;600&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h3 id=&quot;how-to-update&quot; tabindex=&quot;-1&quot;&gt;How to update&lt;/h3&gt;&lt;h4 id=&quot;updating-the-ide-and-plugin&quot; tabindex=&quot;-1&quot;&gt;Updating the IDE and plugin&lt;/h4&gt;&lt;p&gt;Android Studio should have prompted you to update to 3.0, if not then go to &lt;em&gt;Check for updates&lt;/em&gt; in the menu to do so.&lt;/p&gt;&lt;p&gt;Once you launch your project in 3.0 for the first time, you will be told there is a new version of the plugin to update to. You can continue to use your project as it is, but you will miss out on many of the new features and improvements until you update. Simply, follow the prompts to have your project updated to version 3 of the Gradle plugin and to use the latest version of Gradle 4.&lt;/p&gt;&lt;p&gt;If for some reason you need to do this manually:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Open &lt;code&gt;gradle-wrapper.properties&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Enter the latest version of Gradle (above 4.1)&lt;/li&gt;&lt;li&gt;Open &lt;code&gt;build.gradle&lt;/code&gt; in the root of the project&lt;/li&gt;&lt;li&gt;Ensure it contains the Google Maven repository and version 3 of the plugin. &lt;em&gt;Note: there might be a version higher than 3.0.0 available, so use the latest one.&lt;/em&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h4 id=&quot;dependency-configurations&quot; tabindex=&quot;-1&quot;&gt;Dependency configurations&lt;/h4&gt;&lt;p&gt;Previously, when defining dependencies you would use &lt;em&gt;compile.&lt;/em&gt;&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;compile &lt;span class=&quot;token string&quot;&gt;&#39;com.android.support:support-compat:27.0.0&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This has now been deprecated in favour of &lt;code&gt;implementation&lt;/code&gt; and &lt;code&gt;api&lt;/code&gt;. In general, you can simply update all dependencies to use &lt;code&gt;implementation&lt;/code&gt;. However, if your project is a library and it leaks one its module’s interfaces you may need to use &lt;code&gt;api&lt;/code&gt; for that instead.&lt;/p&gt;&lt;p&gt;To understand the difference, please read this &lt;a href=&quot;https://jeroenmols.com/blog/2017/06/14/androidstudio3/&quot;&gt;detailed guide&lt;/a&gt;.&lt;/p&gt;&lt;h4 id=&quot;flavour-dimensions&quot; tabindex=&quot;-1&quot;&gt;Flavour dimensions&lt;/h4&gt;&lt;p&gt;Variants are now automatically matched, which means an app’s debug variant will automatically use a library module debug variant. The same happens for product flavours as well, such as &lt;em&gt;demo&lt;/em&gt; and &lt;em&gt;trial&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;To ensure this mechanism works correctly, it is now required that all product flavours are assigned to a particular flavour dimension. If you don’t need to use different dimensions, you can simply create one and assign all the flavours to it.&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;flavorDimensions &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;/span&gt;

productFlavors &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  prod &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dimension &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  dev &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    dimension &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you use a build type or flavour that doesn’t exist in one of your library modules, a fallback will need to be specified. This isn’t required for &lt;code&gt;debug&lt;/code&gt; or &lt;code&gt;release&lt;/code&gt; as they are present in all modules automatically. The plugin will select the first fallback from the list which is found.&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;debug &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
release &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
staging &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  matchingFallbacks &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;debug&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;release&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;3rd-party-plugins-you-no-longer-need&quot; tabindex=&quot;-1&quot;&gt;3rd party plugins you no longer need&lt;/h4&gt;&lt;p&gt;If you are still using the &lt;code&gt;android-apt&lt;/code&gt; plugin for annotation processing support, you should remove that and use the built-in &lt;code&gt;annotationProcessor&lt;/code&gt;. The third party plugin is no longer supported.&lt;/p&gt;&lt;p&gt;Similarly, many people have been using &lt;code&gt;retrolambda&lt;/code&gt; for Java 8 features support. This is no longer required and will simply be provided automatically, so you should remove the &lt;code&gt;retrolambda&lt;/code&gt; dependency. ✂️&lt;/p&gt;&lt;h4 id=&quot;variant-api-changes&quot; tabindex=&quot;-1&quot;&gt;Variant API changes&lt;/h4&gt;&lt;p&gt;You may find that there are Gradle API changes that remove certain functionality. One area that has some differences is the variant API, which mean you will no longer be able to manipulate variant outputs. This is due to variant-specific tasks no longer being created at configuration time.&lt;/p&gt;&lt;p&gt;If you are using the following Gradle syntax, you should check it is still functioning correctly.&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;applicationVariants&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;all &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; variant &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;firebase-plugin-guava-issue&quot; tabindex=&quot;-1&quot;&gt;Firebase plugin Guava issue&lt;/h4&gt;&lt;p&gt;There is a known issue with the Firebase plugin causing a Guava dependency mismatch. It can be easily fixed by excluding Guava from the Firebase plugin. Only add this if it is needed within your project.&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  classpath &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;com.google.firebase:firebase-plugins:1.1.0&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    exclude group&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;com.google.guava&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;guava-jdk5&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;robolectric-resources-issue&quot; tabindex=&quot;-1&quot;&gt;Robolectric resources issue&lt;/h4&gt;&lt;p&gt;This won’t affect everyone, however, if you are using Robolectric you may find there is a problem with missing resources. To fix this simply add the following to the &lt;code&gt;build.gradle&lt;/code&gt; for your module.&lt;/p&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;testOptions &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  unitTests &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    includeAndroidResources &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;why-should-i-update%3F&quot; tabindex=&quot;-1&quot;&gt;Why should I update?&lt;/h3&gt;&lt;p&gt;There is an endless list of new features and improvements in Android Studio 3.0 and in the new Gradle plugin.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Kotlin programming language support&lt;/li&gt;&lt;li&gt;Android profiler: memory, CPU, network&lt;/li&gt;&lt;li&gt;Java 8 language features built-in&lt;/li&gt;&lt;li&gt;Faster build times&lt;/li&gt;&lt;li&gt;Device file explorer&lt;/li&gt;&lt;li&gt;Instant apps support&lt;/li&gt;&lt;li&gt;Adaptive icon wizard&lt;/li&gt;&lt;li&gt;XML and downloadable fonts&lt;/li&gt;&lt;li&gt;Android Things support&lt;/li&gt;&lt;li&gt;Layout editor improvements&lt;/li&gt;&lt;li&gt;APK profiling and debugging&lt;/li&gt;&lt;li&gt;Layout inspector improvements&lt;/li&gt;&lt;li&gt;Improved Gradle sync speed&lt;/li&gt;&lt;li&gt;AAPT2 is now enabled by default&lt;/li&gt;&lt;li&gt;Firebase app indexing assistant&lt;/li&gt;&lt;li&gt;App links assistants&lt;/li&gt;&lt;/ol&gt;
      </description>
      <pubDate>Sat, 04 Nov 2017 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/welcome-to-android-studio-3-0/</guid>
    </item>    <item>
      <title>Hiring Android Developers</title>
      <link>https://www.lordcodes.com/articles/hiring-android-developers/</link>
      <description>
          &lt;p&gt;Since starting my career as a software developer, I have been to interviews at various companies. I have, however, more often been on the other side of the process: reviewing CVs, analysing code submissions and conducting interviews. On a few different occasions, I have been asked how I think the recruitment process should be structured and what is best to look for in Android developers. These questions don&#39;t have a simple answer that applies to all situations.&lt;/p&gt;&lt;p&gt;Hiring (and unfortunately not hiring) many developers across my working life has helped me to shape the way I approach it. I am by no means an expert and still have plenty to learn from others on the topic, but I believe (and hope) I have some valuable insights that may help other people hiring developers. Therefore, I will attempt to write down some different steps you could include in your hiring process.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/vqWLu8uk_F-600.webp 600w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/vqWLu8uk_F-600.jpeg&quot; alt=&quot;A cartoon candidate taking an Android interview&quot; title=&quot;The Android interview&quot; width=&quot;600&quot; height=&quot;350&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h3 id=&quot;reviewing-cvs&quot; tabindex=&quot;-1&quot;&gt;Reviewing CVs&lt;/h3&gt;&lt;p&gt;This stage shouldn’t come as a surprise to anyone, as obviously you will need some way for candidates to apply for the position. This is the first opportunity for the candidate to tell you why they think they are right for the job.&lt;/p&gt;&lt;p&gt;For some people a CV might be self explanatory, but it is pretty amazing how varied CVs can be. Over time I must have reviewed hundreds of CVs and almost every single CV is different in length, style, format and content. I have seen a few &lt;em&gt;killer&lt;/em&gt; CVs and unfortunately some that weren’t as good.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/KRHgyJ-A9k-490.webp 490w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/KRHgyJ-A9k-490.jpeg&quot; alt=&quot;One does not simply write a perfect CV meme&quot; title=&quot;CVs are hard&quot; width=&quot;490&quot; height=&quot;288&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;When reviewing CVs, it is crucial that you be as fair and objective as possible, avoiding any biases you may have. A good way to achieve this is to compare each CV to the same set of requirements that you have decided are needed to do the job. For an Android developer these may include things like:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Live apps on Google Play&lt;/li&gt;&lt;li&gt;&lt;em&gt;X&lt;/em&gt; years Android development experience&lt;/li&gt;&lt;li&gt;Performing app releases to Google Play&lt;/li&gt;&lt;li&gt;Network communication such as consuming REST APIs&lt;/li&gt;&lt;li&gt;Automation via Continuous Integration services like Bitrise&lt;/li&gt;&lt;li&gt;Automated unit and UI testing&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If possible try to look for a skill rather than its specific application. For example, knowledge of how to consume a REST API, rather than just whether they mention Retrofit and OkHttp. Obviously if a candidate already knows the libraries you use, this can be a great bonus. The focus should, however, be on spotting their level of experience and their ability to learn new skills quickly.&lt;/p&gt;&lt;h3 id=&quot;i%E2%80%99m-not-keen-on-online-tests&quot; tabindex=&quot;-1&quot;&gt;I’m not keen on online tests&lt;/h3&gt;&lt;p&gt;The next stage in the process for many companies can involve some form of online test or screening process such as &lt;a href=&quot;https://www.codility.com/&quot;&gt;Codility&lt;/a&gt;. These tools might make sense for some positions, for example a job that requires intense problem solving or coding quickly under pressure. However, from my experience:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;They are very impersonal.&lt;/li&gt;&lt;li&gt;They can be time consuming and stressful for the candidate.&lt;/li&gt;&lt;li&gt;The problems are rarely similar to the type of work the job entails.&lt;/li&gt;&lt;li&gt;People often do better or worse than they would do in a real-world scenario.&lt;/li&gt;&lt;li&gt;They only check the solution rather than the journey to get there.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I&#39;m not saying these online tests are wrong and should never be used. My preference is just to use other ways to find the right person for the role.&lt;/p&gt;&lt;h3 id=&quot;remote-%2F-phone-%2F-video-interview&quot; tabindex=&quot;-1&quot;&gt;Remote / phone / video interview&lt;/h3&gt;&lt;p&gt;Once you find a candidate that looks promising it is important to meet them as soon as possible. If the number of applications you are receiving is fairly low you could consider going straight to the on-site interview at this stage. In most situations though you will want a remote interview to take place first.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/wWPm5FGRP7-800.webp 800w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/wWPm5FGRP7-800.jpeg&quot; alt=&quot;A man running a phone interview&quot; title=&quot;The phone interview&quot; width=&quot;800&quot; height=&quot;581&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Remote interviews are usually much shorter than their on-site counterpart, preferably something in the region of 30 minutes or less. The shorter length and the fact they are remote can make them much quicker and easier to schedule with the person applying. They can be a good way to quickly gauge the candidate’s experience, their interest in the position and how well they would fit into the team. By having a conversation, it allows them to form a connection with you and the company. Without this having taken place, if another offer comes from elsewhere they would have a lot less driving them to continue the process with you.&lt;/p&gt;&lt;p&gt;Importantly, this shouldn’t feel like an interview and should be as informal as you can manage, allowing the candidate to relax. Some potential talking points:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Their current role&lt;/li&gt;&lt;li&gt;Working on a particular task&lt;/li&gt;&lt;li&gt;Code reviews&lt;/li&gt;&lt;li&gt;Testing&lt;/li&gt;&lt;li&gt;Continuous Integration&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You may also be recruiting for a completely remote position or prefer to do your interviews entirely remotely for ease.&lt;/p&gt;&lt;h3 id=&quot;app-programming&quot; tabindex=&quot;-1&quot;&gt;App programming&lt;/h3&gt;&lt;p&gt;You are looking to hire an Android developer and so the best way to check their technical proficiency is by looking at how they program an Android application. This might seem obvious, but you will find many recruitment processes that rely on object-oriented or functional programming challenges and whiteboard exercises. I gave my stance on online testing earlier, however, there is a key difference here in that the candidate will be programming in Android, using the tools they are familiar with and often in their own time.&lt;/p&gt;&lt;p&gt;The candidate applying may already have examples of their Android development skills via open source app(s) on GitHub, you could consider looking at these instead to make the hiring process quicker for the candidate.&lt;/p&gt;&lt;p&gt;If you do decide to ask the candidate to work on an app project of yours, the app should either be very simple so that they can complete it in a reasonable amount of time or it should already be partially developed. You should also make it clear that they can use whatever approach they want and use whichever libraries they wish. This will allow you to see how they think an Android app should be developed.&lt;/p&gt;&lt;p&gt;There are many advantages to seeing applicant’s Android code before they come in to interview. You can gain insights into their development processes and how they would work as an Android developer. An important consideration though is that completing an app test does increase the amount of effort they have to put in. Therefore, you will have to decide if you think it makes sense for your company to include this in the recruitment process.&lt;/p&gt;&lt;h3 id=&quot;on-site-interviews&quot; tabindex=&quot;-1&quot;&gt;On-site interviews&lt;/h3&gt;&lt;p&gt;This will make up the meat of your hiring process and will likely consist of various stages. The main areas you should consider covering are behavioural (team fit) and technical (skill and experience). Before getting started it is a good idea to describe the general format and timings to the candidate. This helps them to understand how much time they have got and what to expect.&lt;/p&gt;&lt;h4 id=&quot;have-a-conversation&quot; tabindex=&quot;-1&quot;&gt;Have a conversation&lt;/h4&gt;&lt;p&gt;One way of running an interview is that the candidate sits in front of you and is asked a set of different questions, delivering an answer after each one. This approach would only give you answers to your specific questions and would be unnecessarily stressful for the person you are interviewing.&lt;/p&gt;&lt;p&gt;Alternatively, I try to make my interviews as conversational as possible. This means leading things in a certain direction using questions, but allowing the candidate to discuss what they want on the topic. This really shows you how the developer would communicate with other team members and allows them to demonstrate their experience and knowledge to you. By making the questions as open as possible, it will expel the notion that there is a single &lt;em&gt;correct&lt;/em&gt; answer you are looking for. Instead the candidate should relax and open up, telling you their opinion freely on a particular topic. You will even find you learn about new things during these conversations.&lt;/p&gt;&lt;h4 id=&quot;behavioural&quot; tabindex=&quot;-1&quot;&gt;Behavioural&lt;/h4&gt;&lt;p&gt;These types of interviews can often be labelled &lt;em&gt;soft skills&lt;/em&gt; or &lt;em&gt;team fit&lt;/em&gt; interviews. This should in no way diminish the importance of this area of questioning. If you have put the candidate through the app test already the behavioural component could actually be considered the most important part.&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/D5mvA1kfc9-500.webp 500w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/D5mvA1kfc9-500.jpeg&quot; alt=&quot;Tell me about a time when you prepared for a behavioural interview meme&quot; title=&quot;Behavioural interviews need worthwhile questions!&quot; width=&quot;500&quot; height=&quot;500&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;You will ask questions which check the candidate fits with your company culture and the team’s way of working. It will also give the applicant some insight into how the company works. As with reviewing CVs, you should decide which characteristics are most important to you when deciding on your behavioural questions. For example:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Collaboration with other team members&lt;/li&gt;&lt;li&gt;Ability to learn new technologies and skills&lt;/li&gt;&lt;li&gt;Leadership qualities&lt;/li&gt;&lt;li&gt;Communication&lt;/li&gt;&lt;li&gt;How well they can learn from past mistakes&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.lordcodes.com/img/EakkPaAXXB-539.webp 539w&quot;&gt;&lt;img src=&quot;https://www.lordcodes.com/img/EakkPaAXXB-539.jpeg&quot; alt=&quot;What is my worst flaw? I am too awesome!&quot; title=&quot;Asking for general weakness may be a waste of time&quot; width=&quot;539&quot; height=&quot;384&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Please don’t ask all the &lt;em&gt;obvious&lt;/em&gt; questions we all read about online, such as asking about their strengths and weaknesses.&lt;/p&gt;&lt;p&gt;Instead finding out about situations where they:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Had to learn how to use a new library quickly.&lt;/li&gt;&lt;li&gt;Dealt with a team member who strongly disagreed with their opinion on a code review.&lt;/li&gt;&lt;li&gt;Persuaded other team members to introduce a different app architecture.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;technical&quot; tabindex=&quot;-1&quot;&gt;Technical&lt;/h4&gt;&lt;p&gt;How to run effective technical interviews is a very large and heavily discussed topic. You will also find people have many different opinions of how to go about it.&lt;/p&gt;&lt;p&gt;It is very common for interviewers to ask you to write solutions to problems on a whiteboard. Personally, I have never understood this approach as developers don’t generally spend their days finding substrings, detecting palindromes and writing code by hand on the wall.&lt;/p&gt;&lt;p&gt;Any coding you ask the candidate to do should match what they would do if they got the job. This doesn’t mean you have to get them working on the app they would actually work on. It does, however, mean that they work on an Android app, using the tools they would use and in the environment they would work in.&lt;/p&gt;&lt;p&gt;In reality, developers don’t remember absolutely everything and recall it perfectly on the spot. They sometimes forget the signature for a Compose modifier or the name of the Retrofit annotation they need to use. I think it&#39;s a good idea to tell candidates that they can use StackOverflow or the API documentation if they wish.&lt;/p&gt;&lt;p&gt;When working on an Android app, people use libraries like Coroutines, Retrofit and Dagger. This means when they are coding in the interview I think we should make it clear they can use whatever libraries they want to use. You could choose to force them to write plain Android code so you can check they know how to do it. However, I think it&#39;s most valuable to see how they would code in a real-world situation. You may even be able to ask why they chose a particular library or particular approach.&lt;/p&gt;&lt;p&gt;As I mentioned earlier, any technical questioning should be as conversational as possible. I generally write down a few topics I would like to find out about and then nudge the conversation in the right direction using my questions. For example:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Handling a slow internet connection&lt;/li&gt;&lt;li&gt;Automated testing&lt;/li&gt;&lt;li&gt;Dependency Injection&lt;/li&gt;&lt;li&gt;Keeping up-to-date with the world of Android development&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;time-for-questions&quot; tabindex=&quot;-1&quot;&gt;Time for questions&lt;/h4&gt;&lt;p&gt;It is very important that you leave time for candidates to ask you any questions they might have. If the interview was fairly conversational, this may already have been covered. However, if not then it is good to prompt them at the end just to make sure they get the chance to ask any. It is important to remember that you are trying to find the right developer for the team, but they are also trying to find the right company for them.&lt;/p&gt;&lt;h3 id=&quot;closing-thoughts&quot; tabindex=&quot;-1&quot;&gt;Closing thoughts&lt;/h3&gt;&lt;p&gt;As I have said a few times, there are various different ways you can check candidates are right for the position. The techniques you choose to use and the questions you choose to ask, won’t be the same as other interviewers. If carefully put together, the process will help you find some really great developers who are a good fit for the team and for the company.&lt;/p&gt;
      </description>
      <pubDate>Mon, 03 Jul 2017 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Lord</dc:creator>
      <guid>https://www.lordcodes.com/articles/hiring-android-developers/</guid>
    </item>  </channel>
</rss>