<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Callback on sunbro.dev</title><link>https://sunbro.dev/categories/callback/</link><description>Recent content in Callback on sunbro.dev</description><generator>Hugo -- 0.131.0</generator><language>en</language><lastBuildDate>Thu, 09 Mar 2023 22:24:07 +0000</lastBuildDate><atom:link href="https://sunbro.dev/categories/callback/index.xml" rel="self" type="application/rss+xml"/><item><title>Specific callbacks for each element of a RecyclerAdapter</title><link>https://sunbro.dev/posts/2020-04-27-kotlin-method-as-argument/</link><pubDate>Mon, 27 Apr 2020 21:55:45 +0100</pubDate><guid>https://sunbro.dev/posts/2020-04-27-kotlin-method-as-argument/</guid><description>Figuring out how to set a specific callback with RecyclerAdapters</description><content:encoded><![CDATA[<h1 id="premise">Premise</h1>
<p>An Android school project which uses different APIs to get a list of all
Pokémons and information about them. This specific piece of code relates
to a list of all pokémons, or a 
<a href="https://bulbapedia.bulbagarden.net/wiki/National_Pok%C3%A9dex" target="_blank" ><strong>Pokédex</strong></a>.</p>
<p>Specifically, a <code>RecyclerAdapter</code> which sets the <code>OnClickListener</code> for each
row to the same thing:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Kotlin" data-lang="Kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PokedexRecyclerAdapter</span><span class="p">(</span><span class="k">val</span> <span class="py">context</span><span class="p">:</span> <span class="n">Context</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                             <span class="k">val</span> <span class="py">data</span><span class="p">:</span> <span class="n">MutableList</span><span class="p">&lt;</span><span class="n">PokedexEntry</span><span class="p">&gt;):</span>
</span></span><span class="line"><span class="cl">       <span class="nc">RecyclerView</span><span class="p">.</span><span class="n">Adapter</span><span class="p">&lt;</span><span class="nc">PokedexRecyclerAdapter</span><span class="p">.</span><span class="n">ViewHolder</span><span class="p">&gt;()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreateViewHolder</span><span class="p">(</span><span class="n">parent</span><span class="p">:</span> <span class="n">ViewGroup</span><span class="p">,</span> <span class="n">viewType</span><span class="p">:</span> <span class="n">Int</span><span class="p">):</span> <span class="n">ViewHolder</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">val</span> <span class="py">rowView</span> <span class="p">:</span> <span class="n">View</span> <span class="p">=</span> <span class="nc">LayoutInflater</span><span class="p">.</span><span class="n">from</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                             <span class="p">.</span><span class="n">inflate</span><span class="p">(</span><span class="nc">R</span><span class="p">.</span><span class="n">layout</span><span class="p">.</span><span class="n">pokedex_list_item</span><span class="p">,</span> <span class="n">parent</span><span class="p">,</span> <span class="k">false</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">rowView</span><span class="p">.</span><span class="n">setOnClickListener</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="n">context</span> <span class="k">as</span> <span class="n">MainActivity</span><span class="p">).</span><span class="n">onEntryListClicked</span><span class="p">(</span><span class="k">it</span><span class="p">.</span><span class="n">tag</span><span class="p">.</span><span class="n">toString</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">ViewHolder</span><span class="p">(</span><span class="n">rowView</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onBindViewHolder</span><span class="p">(</span><span class="n">holder</span><span class="p">:</span> <span class="n">ViewHolder</span><span class="p">,</span> <span class="n">position</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// [...]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h1 id="problem">Problem</h1>
<p>As each row of the <code>RecyclerView</code> is a different pokémon, in some specific
fragments I needed to change the callback to a specific method call for
each entry.</p>
<p>The method I needed to call looked as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Kotlin" data-lang="Kotlin"><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">fun</span> <span class="nf">setUpSelectedPokemon</span><span class="p">(</span><span class="k">data</span><span class="p">:</span> <span class="n">PokedexEntry</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">selectedPokemon</span> <span class="p">=</span> <span class="k">data</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// Clear second type if new pokémon only has one
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">resetSelectedPokemon</span><span class="p">(</span><span class="k">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">selectedPokemonNameTextView</span><span class="p">.</span><span class="n">text</span> <span class="p">=</span> <span class="k">data</span><span class="p">.</span><span class="n">name</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// [...] More code that configures the selected Pokémon layout elements
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span></code></pre></div><h1 id="solution">Solution</h1>
<p>The first step to fix this is to pass the callback as an argument to the
<code>RecyclerAdapter</code> although the main fix comes from moving the assignment
of the callback from 
<a href="https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter#onCreateViewHolder%28android.view.ViewGroup,%20int%29" target="_blank" ><strong><code>onCreateViewHolder()</code></strong></a>
to 
<a href="https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter#onBindViewHolder%28VH,%20int%29" target="_blank" ><strong><code>onBindViewHolder()</code></strong></a> which has access to the
<code>ViewHolder</code> and the position of the element in the list.</p>
<p>So the <code>RecyclerAdapter</code> now looks like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Kotlin" data-lang="Kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PokedexRecyclerAdapter</span><span class="p">(</span><span class="k">val</span> <span class="py">context</span><span class="p">:</span> <span class="n">Context</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                             <span class="k">val</span> <span class="py">data</span><span class="p">:</span> <span class="n">MutableList</span><span class="p">&lt;</span><span class="n">PokedexEntry</span><span class="p">&gt;,</span>
</span></span><span class="line"><span class="cl">                             <span class="k">val</span> <span class="py">callback</span><span class="p">:</span> <span class="p">((</span><span class="n">PokedexEntry</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Unit</span><span class="p">)?</span> <span class="p">=</span> <span class="k">null</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">       <span class="nc">RecyclerView</span><span class="p">.</span><span class="n">Adapter</span><span class="p">&lt;</span><span class="nc">PokedexRecyclerAdapter</span><span class="p">.</span><span class="n">ViewHolder</span><span class="p">&gt;()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onCreateViewHolder</span><span class="p">(</span><span class="n">parent</span><span class="p">:</span> <span class="n">ViewGroup</span><span class="p">,</span> <span class="n">viewType</span><span class="p">:</span> <span class="n">Int</span><span class="p">):</span> <span class="n">ViewHolder</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">val</span> <span class="py">rowView</span> <span class="p">:</span> <span class="n">View</span> <span class="p">=</span> <span class="nc">LayoutInflater</span><span class="p">.</span><span class="n">from</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                             <span class="p">.</span><span class="n">inflate</span><span class="p">(</span><span class="nc">R</span><span class="p">.</span><span class="n">layout</span><span class="p">.</span><span class="n">pokedex_list_item</span><span class="p">,</span> <span class="n">parent</span><span class="p">,</span> <span class="k">false</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">ViewHolder</span><span class="p">(</span><span class="n">rowView</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">fun</span> <span class="nf">onBindViewHolder</span><span class="p">(</span><span class="n">holder</span><span class="p">:</span> <span class="n">ViewHolder</span><span class="p">,</span> <span class="n">position</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// [...]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">callback</span> <span class="o">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">holder</span><span class="p">.</span><span class="n">itemView</span><span class="p">.</span><span class="n">setOnClickListener</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">callback</span><span class="o">!!</span><span class="p">(</span><span class="k">data</span><span class="p">[</span><span class="n">position</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">holder</span><span class="p">.</span><span class="n">itemView</span><span class="p">.</span><span class="n">setOnClickListener</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="p">(</span><span class="n">context</span> <span class="k">as</span> <span class="n">MainActivity</span><span class="p">).</span><span class="n">onEntryListClicked</span><span class="p">(</span><span class="k">it</span><span class="p">.</span><span class="n">tag</span><span class="p">.</span><span class="n">toString</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Which can then be called like this from our <code>Fragment</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Kotlin" data-lang="Kotlin"><span class="line"><span class="cl"><span class="n">pokemonListRecyclerView</span><span class="p">.</span><span class="n">adapter</span> <span class="p">=</span> 
</span></span><span class="line"><span class="cl"><span class="n">PokedexRecyclerAdapter</span><span class="p">(</span><span class="n">activity</span> <span class="k">as</span> <span class="n">MainActivity</span><span class="p">,</span> <span class="k">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                          <span class="p">{</span> <span class="n">elt</span> <span class="o">-&gt;</span> <span class="n">setUpSelectedPokemon</span><span class="p">(</span><span class="n">elt</span><span class="p">)</span> <span class="p">}</span>
</span></span></code></pre></div>]]></content:encoded></item></channel></rss>