<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/stjepan-banek/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Tue, 14 Apr 2026 10:32:35 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>25200https://infinum.com/uploads/2022/06/JsonX-optimized.webp</url>
				</image>
				<title>A Kotlin-First JSON API Library – JsonApiX</title>
				<link>https://infinum.com/blog/a-kotlin-first-json-api-library-jsonapix/</link>
				<pubDate>Fri, 03 Jun 2022 09:54:05 +0000</pubDate>
				<dc:creator>Stjepan Banek</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=25200</guid>
				<description>
					<![CDATA[<p>The Kotlin community was missing a fresh, easy-to-use and Kotlin-first JSON:API implementation. </p>
<p>The post <a href="https://infinum.com/blog/a-kotlin-first-json-api-library-jsonapix/">A Kotlin-First JSON API Library – JsonApiX</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-324"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	<a href="https://jsonapi.org/">JSON:API is a widely used specification</a> for modeling client–server API&#8217;s. It’s built on top of the JSON notation standard, to make sharing objects with relationships and all other relevant information such as errors, links, and meta data standardized. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-97'
	>
	However, in Kotlin, it has been poorly covered by libraries that would make the use of JSON:API easier for the developer.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-100"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-24-text js-typography block-highlighted-text__typography'
	data-id='es-99'
	>
	When we set out on this project, we believed that the Kotlin community was missing a fresh, easy-to-use and Kotlin-first JSON:API implementation.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-103"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-101">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-102'
	>
	While considering how to make the usage as simple as possible, we decided to go with the annotation processor and code generation approach. The goal was to come up with a set of annotations that would make the bridge between Kotlin classes and JSON:API, without any additional effort. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-106"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-104">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-105'
	>
	As will be shown in this article, our <a href="https://github.com/infinum/kotlin-jsonapix">JsonApiX<strong> </strong>library</a><strong> </strong>has achieved just that.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-109"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-107">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-108'
	>
	General info</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-112"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-110">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-111'
	>
	JsonApiX is an annotation processor library made on top of the <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md">Kotlinx serialization</a>, to make implementing JSON:API specification much easier. With the use of just a few annotations, it generates JSON:API wrappers for the Kotlin classes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-115"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-113">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-114'
	>
	Wrappers are modeled in a way to follow the JSON:API specification format, using the annotated class’s properties to model the data and relationships part. They are serializable, so parsing in both directions is supported.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-118"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-116">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-117'
	>
	The library also has a retrofit module, with a converter to support the API implementations.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-121"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-119">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-120'
	>
	It was built for Kotlin, so it can be used on all Kotlin based projects such as Android apps and Kotlin multiplatform apps.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-124"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-122">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-123'
	>
	Basic usage</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-127"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-125">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-126'
	>
	Let’s take the example of a simple class called <code>Book</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-129"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">JsonApiX</span><span class="token">(</span><span class="token" style="color: #005cc5;">type</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Serializable</span><span class="token">
</span></span><span class="line"><span class="token">data </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Book</span><span class="token">(
</span></span><span class="line"><span class="token">   val name: String,
</span></span><span class="line"><span class="token">   val pageCount: Int
</span></span><span class="line"><span class="token">)
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-132"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-130">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-131'
	>
	<code>Book</code> has two simple parameters: <code>name</code> and <code>pageCount</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-135"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-133">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-134'
	>
	Every class annotated with <code>@JsonApiX</code> needs to also be annotated with <code>@Serializable</code> , because JsonApiX is leveraging the Kotlinx serialization to serialize and deserialize classes.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-138"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-136">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-137'
	>
	<code>@JsonApiX</code> takes a <code>type</code> parameter, which is one of the mandatory JSON:API parameters, and its value will be used as the value for the key <code>type</code> in the output.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-141"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-139">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-140'
	>
	When we annotate a class with the <code>@JsonApiX</code> annotation, the processor will generate the implementations of a number of interfaces, based on the annotated class. They are made to convert it to the JSON:API format and offer a way to parse it.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-144"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-142">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-143'
	>
	Two most important interfaces are shown below.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-146"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">JsonApiX</span><span class="token">&lt;</span><span class="token" style="color: #d73a49;">out</span><span class="token"> </span><span class="token" style="color: #d73a49;">Model</span><span class="token">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   val data</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #24292e;">ResourceObject</span><span class="token">&lt;</span><span class="token" style="color: #d73a49;">Model</span><span class="token">&gt;</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">   val included</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #24292e;">List</span><span class="token">&lt;</span><span class="token" style="color: #24292e;">ResourceObject</span><span class="token">&lt;</span><span class="token">*</span><span class="token">&gt;</span><span class="token">&gt;</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">   val errors</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #24292e;">List</span><span class="token">&lt;</span><span class="token" style="color: #d73a49;">Error</span><span class="token">&gt;</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">   val links</span><span class="token" style="color: #d73a49;">:</span><span class="token"> Links</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">   val meta</span><span class="token" style="color: #d73a49;">:</span><span class="token"> Meta</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-149"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-147">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-148'
	>
	<code>JsonApiX</code> interface is a root-level wrapper for a class. Data property wraps the primitive attributes of the original class and relationship references. Included array contains the data of the relationships if any are present. Other properties of this interface are optional fields from the JSON:API specification. Every generated implementation is serializable, allowing the serialization and deserialization of all the parameters from the specification.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-152"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-150">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-151'
	>
	Along with the wrappers, the library also generates helper functions and extensions to support the serialization/deserialization processes. Aiming to prevent the developers from having to know and use them, we’ve come up with the idea of an adapter. For each annotated class, an adapter implementation will be generated, as a composition of all the operations needed in the serialization/deserialization process.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-155"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-153">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-154'
	>
	Here is the interface we use for the adapter implementations with its most important methods.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-157"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">TypeAdapter</span><span class="token">&lt;</span><span class="token" style="color: #d73a49;">Model</span><span class="token">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">convertFromStrin</span><span class="token" style="color: #6f42c1;">g</span><span class="token">(</span><span class="token" style="color: #e36209;">input</span><span class="token">: </span><span class="token" style="color: #e36209;">String</span><span class="token">)</span><span class="token">: Model
</span></span><span class="line"><span class="token">   </span><span class="token">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">convertToStrin</span><span class="token" style="color: #6f42c1;">g</span><span class="token">(</span><span class="token" style="color: #e36209;">input</span><span class="token">: </span><span class="token" style="color: #e36209;">Model</span><span class="token">)</span><span class="token">: String
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-160"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-158">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-159'
	>
	To get the type adapter for your specific class, use the generated TypeAdapterFactory class.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-162"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Gets adapter for a single instance of Book</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val adapter </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #6f42c1;">TypeAdapterFactory</span><span class="token">(</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getAdapter</span><span class="token">(</span><span class="token">Book</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #d73a49;">:</span><span class="token">class</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Gets adapter for a list of Book instances</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">val listAdapter </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #6f42c1;">TypeAdapterFactory</span><span class="token">(</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #6f42c1;">getListAdapter</span><span class="token">(</span><span class="token">Book</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #d73a49;">:</span><span class="token">class</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">adapter</span><span class="token">.</span><span class="token" style="color: #6f42c1;">convertToString</span><span class="token">(</span><span class="token">book</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Produces JSON API String from a Book instance</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #24292e;">adapter</span><span class="token">.</span><span class="token" style="color: #6f42c1;">convertFromString</span><span class="token">(</span><span class="token">input</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Produces Book instance from JSON:API String</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #24292e;">listAdapter</span><span class="token">.</span><span class="token" style="color: #6f42c1;">convertToString</span><span class="token">(</span><span class="token">books</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Produces JSON:API String from a Book list</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #24292e;">listAdapter</span><span class="token">.</span><span class="token" style="color: #6f42c1;">convertFromString</span><span class="token">(</span><span class="token">input</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Produces Book list from JSON:API String</span><span class="token" style="color: #6a737d;">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-165"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-163">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-164'
	>
	Now, let’s extend our model and take a look at how to handle relationships in our classes. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-167"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">JsonApiX</span><span class="token">(</span><span class="token" style="color: #005cc5;">type</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Serializable</span><span class="token">
</span></span><span class="line"><span class="token">data </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Book</span><span class="token">(
</span></span><span class="line"><span class="token">   val name: String,
</span></span><span class="line"><span class="token">   val pageCount: Int,
</span></span><span class="line"><span class="token">   @HasOne(type = &quot;author&quot;)
</span></span><span class="line"><span class="token">   val author: Author,
</span></span><span class="line"><span class="token">   @HasMany(type = &quot;character&quot;)
</span></span><span class="line"><span class="token">   val characters: List</span><span class="token">&lt;</span><span class="token" style="color: #d73a49;">Character</span><span class="token">&gt;</span><span class="token">
</span></span><span class="line"><span class="token">)
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-170"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-168">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-169'
	>
	Our Book now has an author and a list of characters. Both of these attributes are classes themselves, so they need to be treated as relationships.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-172"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-20-text js-typography block-highlighted-text__typography'
	data-id='es-171'
	>
	Important note: Relationship models need to also be annotated with both @JsonApiX and @Serializable. The type parameter in @JsonApiX of the relationship model needs to match the one in @HasOne/@HasMany annotations. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-175"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-173">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-174'
	>
	Generated wrappers and adapters will now account for the relationships in serialization and deserialization. No additional work is needed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-177"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-20-text js-typography block-highlighted-text__typography'
	data-id='es-176'
	>
	Important note: When deserializing relationships, JsonApiX relies on the included array from the JSON:API specification. If the relationship is non-nullable and missing from the included array, a JsonApiXMissingArgumentException will be thrown.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-180"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-178">
	<h3	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-179'
	>
	Nullability</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-183"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-181">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-182'
	>
	Our Book model looks great now, right? However, do all books necessarily have characters? I don&#8217;t think so, and I&#8217;m speaking from personal experience – as a person who read a couple of physics books while studying. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-186"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-184">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-185'
	>
	Let’s make a small change in our Book model and make the characters list nullable.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-188"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">JsonApiX</span><span class="token">(</span><span class="token" style="color: #005cc5;">type</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Serializable</span><span class="token">
</span></span><span class="line"><span class="token">data </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Book</span><span class="token">(
</span></span><span class="line"><span class="token">   val name: String,
</span></span><span class="line"><span class="token">   val pageCount: Int,
</span></span><span class="line"><span class="token">   @HasOne(type = &quot;author&quot;)
</span></span><span class="line"><span class="token">   val author: Author,
</span></span><span class="line"><span class="token">   @HasMany(type = &quot;character&quot;)
</span></span><span class="line"><span class="token">   val characters: List</span><span class="token">&lt;</span><span class="token" style="color: #d73a49;">Character</span><span class="token">&gt;</span><span class="token">?
</span></span><span class="line"><span class="token">)
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-191"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-189">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-190'
	>
	As I mentioned before, all non-nullable relationships must be present in the included array of the JSON:API input. Otherwise, the deserialization process will fail.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-194"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-192">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-193'
	>
	However, nullable relationships do not suffer the same fate. They will simply be assigned to <code>null</code> if the input is missing their data.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-197"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-195">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-196'
	>
	We’ve made our deserialization process with nullable properties in mind, so it’s safe to have nullable attributes, both primitive and relationships. The JSON:API input can be deserialized without their values.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-200"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-198">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-199'
	>
	For example, the following JSON:API input:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-202"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">data</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">type</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">id</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">1</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">attributes</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">         </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">name</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">The Fellowship Of The Ring</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">         </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">pageCount</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #005cc5;">432</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">relationships</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">         </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">author</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">data</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">               </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">type</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">author</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">               </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">id</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">4</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">         </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">included</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token">[</span><span class="token">
</span></span><span class="line"><span class="token">         </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">type</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">author</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">id</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">4</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">attributes</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">               </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">name</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #d73a49;">:</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">J.R.R. Tolkien</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">         </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-205"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-203">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-204'
	>
	Will be successfully parsed to a Book instance with characters list assigned to <code>null</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-208"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-206">
	<h3	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-207'
	>
	Errors</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-211"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-209">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-210'
	>
	According to the JSON:API specification, each object should have an optional errors array. The following interface is used as a root-level wrapper for JSON:API responses. It contains a nullable errors list.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-213"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">JsonApiX</span><span class="token">&lt;</span><span class="token" style="color: #d73a49;">out</span><span class="token"> </span><span class="token" style="color: #d73a49;">Model</span><span class="token">&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    val data</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #24292e;">ResourceObject</span><span class="token">&lt;</span><span class="token" style="color: #24292e;">M</span><span class="token" style="color: #d73a49;">odel</span><span class="token">&gt;</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">    val included</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #24292e;">List</span><span class="token">&lt;</span><span class="token" style="color: #24292e;">R</span><span class="token" style="color: #24292e;">esourceObject</span><span class="token">&lt;</span><span class="token">*</span><span class="token">&gt;</span><span class="token">&gt;</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">    val errors</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #24292e;">List</span><span class="token">&lt;</span><span class="token" style="color: #24292e;">E</span><span class="token" style="color: #d73a49;">rror</span><span class="token">&gt;</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">    val links</span><span class="token" style="color: #d73a49;">:</span><span class="token"> Links</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">    val meta</span><span class="token" style="color: #d73a49;">:</span><span class="token"> Meta</span><span class="token" style="color: #d73a49;">?</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-216"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-214">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-215'
	>
	A single error is modeled to wrap the most common arguments of an error. In the future, we plan to extend the error model with some optional fields, and give the developers an ability to model their custom errors.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-218"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Error</span><span class="token">(
</span></span><span class="line"><span class="token">    val code: String,
</span></span><span class="line"><span class="token">    val title: String,
</span></span><span class="line"><span class="token">    val detail: String,
</span></span><span class="line"><span class="token">    val status: String
</span></span><span class="line"><span class="token">)
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-221"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-219">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-220'
	>
	When using Retrofit in the event of a network error, a <code>HttpException</code> will be thrown. To extract the <code>Error</code> model from a response, you can use the <code>HttpException.asJsonXHttpException()</code> extension, which will then return a <code>JsonXHttpException</code>, containing the original response as well as the errors list.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-223"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">try</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    val book </span><span class="token" style="color: #d73a49;">=</span><span class="token"> io </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #24292e;">sampleApiService</span><span class="token" style="color: #6f42c1;">.fetchBo</span><span class="token" style="color: #6f42c1;">o</span><span class="token">k(</span><span class="token">)</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token"> </span><span class="token" style="color: #d73a49;">catch</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #24292e;">exception</span><span class="token">: </span><span class="token" style="color: #e36209;">HttpException</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    val errors </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">exception</span><span class="token">.asJsonXHttpException</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #24292e;">.error</span><span class="token">s</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Handle errors</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-226"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-224">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-225'
	>
	Advanced usage</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-229"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-227">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-228'
	>
	JSON:API specification includes resources that are not necessarily a part of the original models. For that reason, JsonApiX provides a way to retrieve the links and meta values from the JSON:API input without including those fields in your model. To achieve this, your model needs to extend the <code>JsonApiModel</code> abstract class.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-231"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">JsonApiX</span><span class="token">(</span><span class="token" style="color: #005cc5;">type</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Serializable</span><span class="token">
</span></span><span class="line"><span class="token">data </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Book</span><span class="token">(
</span></span><span class="line"><span class="token">   val name: String,
</span></span><span class="line"><span class="token">   val pageCount: Int,
</span></span><span class="line"><span class="token">   @HasOne(type = &quot;author&quot;)
</span></span><span class="line"><span class="token">   val author: Author,
</span></span><span class="line"><span class="token">   @HasMany(type = &quot;character&quot;)
</span></span><span class="line"><span class="token">   val characters: List</span><span class="token">&lt;</span><span class="token" style="color: #d73a49;">Character</span><span class="token">&gt;</span><span class="token">?
</span></span><span class="line"><span class="token">) : JsonApiModel()
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-234"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-232">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-233'
	>
	<code>JsonApiModel</code> is an abstract class which will provide you with getters and setters for links and meta objects.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-237"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-235">
	<h3	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-236'
	>
	Links</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-240"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-238">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-239'
	>
	JsonApiX currently supports retrieving links from the root object, relationships and resource object(<code>data</code> key) from the JSON:API specification. By default, the links model has the following implementation.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-242"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">DefaultLinks</span><span class="token">(
</span></span><span class="line"><span class="token">    val self: String? = null,
</span></span><span class="line"><span class="token">    val related: String? = null,
</span></span><span class="line"><span class="token">    val first: String? = null,
</span></span><span class="line"><span class="token">    val last: String? = null,
</span></span><span class="line"><span class="token">    val next: String? = null,
</span></span><span class="line"><span class="token">    val prev: String? = null
</span></span><span class="line"><span class="token">) : Links
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-245"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-243">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-244'
	>
	And they can be retrieved in the following way.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-247"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Get root level links</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #24292e;">person</span><span class="token">.</span><span class="token" style="color: #6f42c1;">rootLinks</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Get relationships links</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #24292e;">person</span><span class="token">.</span><span class="token" style="color: #6f42c1;">relationshipsLinks</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Get resource object links</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #24292e;">person</span><span class="token">.</span><span class="token" style="color: #6f42c1;">resourceLinks</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-250"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-248">
	<h3	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-249'
	>
	Custom links</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-253"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-251">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-252'
	>
	Developers can define their own custom link models to adapt to their specific requirements. Let&#8217;s take this custom Book links model as an example. Every custom links model must extend the <code>Links</code> interface and have a <code>JsonApiXLinks</code> annotation.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-255"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Serializable</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">JsonApiXLinks</span><span class="token">(</span><span class="token" style="color: #005cc5;">type</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">placementStrategy</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">LinksPlacementStrategy</span><span class="token">.</span><span class="token" style="color: #24292e;">ROOT</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">data </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">BookLinks</span><span class="token">(
</span></span><span class="line"><span class="token">   val authorBioLink: String,
</span></span><span class="line"><span class="token">   val bookStoreLink: String
</span></span><span class="line"><span class="token">)
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-258"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-256">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-257'
	>
	In this example, the annotation processor will automatically make the root-links type of a <code>Book</code> class to be BookLinks.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-261"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-259">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-260'
	>
	Developers need to make sure that the <code>type</code> parameter value in <code>JsonApiXLinks</code> matches the one in the <code>JsonApiX</code> annotation of the original model. <br></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-264"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-262">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-263'
	>
	To retrieve them, a generic variant of the <code>rootLinks()</code> method is used.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-266"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Gets root level links as a BookLinks instance</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #24292e;">person</span><span class="token">.</span><span class="token" style="color: #24292e;">rootLinks</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token">BookLinks</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-269"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-267">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-268'
	>
	<code>LinksPlacementStartegy</code> enum is used to determine which links from the whole JSON:API object will be replaced by a custom model. It currently supports <code>ROOT</code>, <code>RELATIONSHIPS</code> and <code>DATA</code> links.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-272"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-270">
	<h3	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-271'
	>
	Meta object</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-275"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-273">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-274'
	>
	In JSON:API specification, meta is an optional object. Unlike links, it doesn&#8217;t have a predefined default model. For that reason, in order to use the meta feature, the developer must define a custom meta model for each class with which he wants to use it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-278"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-276">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-277'
	>
	<br>Let&#8217;s take the <code>BookMeta</code> model as an example. Every custom meta model must extend the <code>Meta</code> interface and have a <code>JsonApiXMeta</code> annotation, with its type parameter matching the one from the <code>JsonApiX</code> annotation of the original model.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-280"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">Serializable</span><span class="token">
</span></span><span class="line"><span class="token">@</span><span class="token" style="color: #d73a49;">JsonApiXMeta</span><span class="token">(</span><span class="token" style="color: #005cc5;">type</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">data </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">BookMeta</span><span class="token">(
</span></span><span class="line"><span class="token">   val publisherName: String
</span></span><span class="line"><span class="token">) : Meta
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-283"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-281">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-282'
	>
	In this example, the annotation processor will automatically make the meta type of a <code>Book</code> class to be <code>BookMeta</code>. To retrieve a meta object, a generic variant of the <code>meta()</code> method is used.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-285"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Gets the meta object</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #24292e;">book</span><span class="token">.</span><span class="token" style="color: #24292e;">meta</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token">BookMeta</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-288"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-286">
	<h3	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-287'
	>
	Retrofit</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-291"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-289">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-290'
	>
	To enable the Retrofit integration, JsonApiX generates the converter implementation which can be added to the retrofit builder. It takes an instance of <code>TypeAdapterFactory</code> as a parameter. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-293"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #24292e;">Retrofit</span><span class="token">.</span><span class="token" style="color: #6f42c1;">Builder</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6f42c1;">.addConverterFac</span><span class="token" style="color: #6f42c1;">t</span><span class="token" style="color: #6f42c1;">or</span><span class="token">y(</span><span class="token" style="color: #6f42c1;">JsonXConverterFac</span><span class="token" style="color: #6f42c1;">t</span><span class="token" style="color: #6f42c1;">ory</span><span class="token">(</span><span class="token" style="color: #6f42c1;">TypeAdapterFac</span><span class="token" style="color: #6f42c1;">t</span><span class="token" style="color: #6f42c1;">ory</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6f42c1;">.bas</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">Ur</span><span class="token">l(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">https://www.example.com</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6f42c1;">.b</span><span class="token" style="color: #6f42c1;">u</span><span class="token" style="color: #6f42c1;">il</span><span class="token">d(</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-296"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-294">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-295'
	>
	<code>JsonXConverterFactory</code> converts the input all the way down (or up) to the original model, so there is no need for any additional wrappers in the API service definition. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-298"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-java github-light" data-language="java" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">SampleApiService</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">@</span><span class="token" style="color: #d73a49;">GE</span><span class="token">T(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">fetch</span><span class="token" style="color: #6f42c1;">B</span><span class="token" style="color: #6f42c1;">ook</span><span class="token">(</span><span class="token">)</span><span class="token">: Book
</span></span><span class="line"><span class="token">    
</span></span><span class="line"><span class="token">    @</span><span class="token" style="color: #6f42c1;">P</span><span class="token" style="color: #6f42c1;">OST</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">/create-book</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">postNew</span><span class="token" style="color: #6f42c1;">B</span><span class="token" style="color: #6f42c1;">ook</span><span class="token">(</span><span class="token" style="color: #d73a49;">@Bod</span><span class="token">y</span><span class="token"> </span><span class="token" style="color: #e36209;">book</span><span class="token">: </span><span class="token" style="color: #e36209;">Book</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-301"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-299">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-300'
	>
	Annotations summary table</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-304"
	 data-animation-target='inner-items'>
		
			<div class="block-group" data-id=es-303>
	
<div
	class="wrapper"
	data-id="es-302"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			
<figure class="wp-block-table"><table><thead><tr><th><strong>Annotation</strong></th><th><strong>Target</strong></th><th><strong>Interface to extend</strong></th><th><strong>Description</strong></th></tr></thead><tbody><tr><td>@JsonApiX</td><td>Class</td><td>None</td><td>Generates JSON:API wrappers and adapters for the target class</td></tr><tr><td>@HasOne</td><td>Class field</td><td>None</td><td>Indicates that a class field is a one-relationship</td></tr><tr><td>@HasMany</td><td>Class field</td><td>None</td><td>Indicates that a class field is a many-relationship</td></tr><tr><td>@JsonApiXLinks</td><td>Class</td><td>Links</td><td>Indicates that a target class should be used as a <strong>links</strong> model for its owner model</td></tr><tr><td>@JsonApiXMeta</td><td>Class</td><td>Meta</td><td>Indicates that a target class should be used as a <strong>meta</strong> model for its owner model</td></tr></tbody></table></figure>
		</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-307"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-305">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-306'
	>
	You’ll go a long way, library</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-310"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-308">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-309'
	>
	Making this library was a long and exciting journey for me and my colleagues. We had to overcome many challenges, and I can’t even count how many times I was busting my head for hours, even days, over some parsing issue.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-313"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-311">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-312'
	>
	We give great thanks to the creators of <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md">Kotlinx serialization</a> and <a href="https://square.github.io/kotlinpoet/">Kotlin poet</a>, because our work is heavily based on the features of those libraries. However, the journey is still not over, it’s rather just starting. And we have big plans for the future of the library.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-316"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-314">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-315'
	>
	Some of the most exciting upgrades we are planning to do are:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-319"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-317">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-318'
	>
	<li>Kotlin symbol processing support</li><li>Expanding the <code>JsonApiModel</code> API with more customizations and data</li><li>Custom error models</li><li>Many more&#8230;</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-322"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-320">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-321'
	>
	We welcome your contributions, so we’ve decided to <a href="https://github.com/infinum/kotlin-jsonapix">make this library open-source</a>! Feel free to peek through the code and open pull request.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/a-kotlin-first-json-api-library-jsonapix/">A Kotlin-First JSON API Library – JsonApiX</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>8025https://infinum.com/uploads/2021/08/hak-camera-integration-0.webp</url>
				</image>
				<title>Camera Integration in the HAK Driving Exam App</title>
				<link>https://infinum.com/blog/hak-camera-integration/</link>
				<pubDate>Tue, 03 Aug 2021 10:45:00 +0000</pubDate>
				<dc:creator>Stjepan Banek</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/hak-camera-integration/</guid>
				<description>
					<![CDATA[<p>Another pair of eyes keeping an eye on the road for new drivers.</p>
<p>The post <a href="https://infinum.com/blog/hak-camera-integration/">Camera Integration in the HAK Driving Exam App</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-620"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-325">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-328"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-326">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-327'
	>
	The Croatian Automobile Club (HAK) oversees and carries out all driving exams in Croatia. To introduce a digital dimension to the whole process, <a href="https://infinum.com/news/hak-app/">Infinum built an application that helps the examiners track the course of an exam</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-331"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-329">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-330'
	>
	The app notes the applicant’s mistakes, exam duration, driving path and records the exam using a third-party WiFi camera connected to the tablet while the app is used.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-334"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-332">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-333'
	>
	In this article, we will focus on the camera implementation aspect.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-337"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-335">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-336'
	>
	Camera implementation challenges</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-340"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-338">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-339'
	>
	The development process wasn’t free of hurdles. The first significant one was WiFi discovery and connection. We realized that there was no cohesive and understandable API before Android 10 to perform these tasks. Eventually we came up with a solution, but in all honesty, we had a complete mess on our hands.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-343"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-341">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-342'
	>
	We had to use dozens of deprecated methods and properties as well as massive methods with a lot of try/catch clauses just to get our app to scan for a camera and connect with one. We were also worried about a deprecation notice saying that the app-initiated WiFi scans are going to be completely removed in future versions. However, there is no need to dive into pre-Android 10 network API in this article.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-346"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-344">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-345'
	>
	Somewhere along the road we decided to move the minimum version of the app to Android 10. We could afford to do so, because HAK examiners use only one type of device, and that device was updated to Android 10. This also allowed us to obtain access to <a href="https://developer.android.com/reference/android/net/wifi/WifiNetworkSpecifier">WifiNetworkSpecifier API</a>, which helped a great deal.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-349"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-347">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-348'
	>
	We discovered some more challenges in the recording feature:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-352"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-350">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-351'
	>
	<li>Connecting the camera to the application over TCP</li><li>Implementing a client to send commands to the camera and receive responses</li><li>Streaming the live camera feed to the app</li><li>Maintaining and restoring the connection if something goes wrong</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-355"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-353">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-354'
	>
	The dashcam</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-358"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-356">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-357'
	>
	For the recording feature we decided to use a car digital video recorder or a dashcam. The camera is placed on the car’s dashboard or windshield and connected to the app over WiFi.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-361"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-359">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-360'
	>
	These are the camera’s features:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-364"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-362">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-363'
	>
	<li>WiFi connectable</li><li>Recording to an SD card</li><li>Streaming the feed over WiFi</li><li>Removable SD card to store the videos</li><li>Command interface to communicate with the client app</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-367"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-365">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-366'
	>
	The camera connects to the application over WiFi. The user can control the recording through that connection and send some additional commands. Two connections are made with the camera:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-370"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-368">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-369'
	>
	<li>TCP socket connection for sending commands and receiving responses. For example, requesting and receiving info about the available storage data is done this way, as well as setting the exam ID for the video and starting or stopping the recording.</li><li>HTTP connection for streaming the camera feed to the application.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-373"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-371">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-372'
	>
	When the recording is initiated, the camera records videos and stores them on the SD card. Each recording session is stored in a separate folder for easier navigation and the videos are recorded in multiple 1-minute recordings. Each video has a timestamp and the exam’s ID so that they can be sorted for each exam.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-376"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-374">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-375'
	>
	WiFi Network Specifier API</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-379"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-377">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-378'
	>
	Android 10 introduced a new API to handle in-app <a href="https://developer.android.com/guide/topics/connectivity/wifi-bootstrap">WiFi connections</a>. In-app connection here means literaly that. The connection is established while the application is used and then automatically disconnected when the application is closed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-382"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-380">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-381'
	>
	Thanks to the new API, the whole process became much easier to implement.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-385"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-383">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-384'
	>
	Let’s dive into it step by step:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-388"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-386">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-387'
	>
	Building a specifier</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-390"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">specifier</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">WifiNetworkSpecifier</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">Builder</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">setSsidPattern</span><span class="token">(</span><span class="token" style="color: #6f42c1;">PatternMatcher</span><span class="token">(</span><span class="token" style="color: #005cc5;">ssid</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">PatternMatcher</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">PATTERN_PREFIX</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">setWpa2Passphrase</span><span class="token">(</span><span class="token" style="color: #005cc5;">password</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">build</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-393"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-391">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-392'
	>
	<em>WifiNetworkSpecifier</em> is a kind of a query object for available network connections. We specified the SSID (name) of the network we wanted to connect to in its builder.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-396"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-394">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-395'
	>
	In this case we had predefined SSID patterns for our dashcams so that’s what we were passing in the variable SSID.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-399"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-397">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-398'
	>
	<em>PatternMatcher.PATTERN_PREFIX</em> is a constant that says we will use the value passed in SSID and use it as a prefix for possible access points. Access points that do not start with the SSID value are ignored.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-402"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-400">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-401'
	>
	For example:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-405"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-403">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-404'
	>
	<code>val ssid = "Dashcam_"</code></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-408"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-406">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-407'
	>
	Available networks:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-411"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-409">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-410'
	>
	<li>Dashcam_123</li><li>My Home Wifi</li><li>Office</li><li>Dashcam_234</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-414"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-412">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-413'
	>
	Networks shown by the WiFi connection dialog:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-417"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-415">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-416'
	>
	<li>Dashcam_123</li><li>Dashcam_234</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-420"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-418">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-419'
	>
	We filtered out all access points that are not a dashcam. Optionally, we could have added a password so the connection is established faster. Otherwise, the dialog asks for password input. In our case the passwords were also predefined, so we used:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-423"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-421">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-422'
	>
	<code>setWpa2Passphrase(password)</code></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-426"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-424">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-425'
	>
	Building a NetworkRequest</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-429"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-427">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-428'
	>
	After specifying the access point, we needed to build a <em>NetworkRequest</em> object with some additional configuration for our connection. First, we set the transport type to <em>TRANSPORT_WIFI</em>, by which we said that the connection would be established over WiFi. We then removed the connection’s internet capability, as our camera and application were communicating peer-to-peer. We finally added the specifier that we had built earlier to <em>NetworkRequest</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-431"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">request</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">NetworkRequest</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">Builder</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">addTransportType</span><span class="token">(</span><span class="token" style="color: #005cc5;">NetworkCapabilities</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">TRANSPORT_WIFI</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">removeCapability</span><span class="token">(</span><span class="token" style="color: #005cc5;">NetworkCapabilities</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">NET_CAPABILITY_INTERNET</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">setNetworkSpecifier</span><span class="token">(</span><span class="token" style="color: #005cc5;">specifier</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">build</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-434"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-432">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-433'
	>
	With everything set up, let’s move on to requesting a connection using <em>ConnectivityManager</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-437"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-435">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-436'
	>
	Requesting a network connection</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-440"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-438">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-439'
	>
	Since it is a fairly simple procedure, we decided to use <em>ConnectivityManager</em> and define a callback to handle all the outcomes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-442"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">networkCallback</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">object</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">ConnectivityManager</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">NetworkCallback</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onAvailable</span><span class="token">(</span><span class="token" style="color: #6f42c1;">network</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Network</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle success</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onUnavailable</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle failure</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onLosing</span><span class="token">(</span><span class="token" style="color: #6f42c1;">network</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Network</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">maxMsToLive</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">Int</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle losing connection</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onLost</span><span class="token">(</span><span class="token" style="color: #6f42c1;">network</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Network</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle lost connection</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onLinkPropertiesChanged</span><span class="token">(</span><span class="token" style="color: #6f42c1;">network</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Network</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">linkProperties</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">LinkProperties</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle network changing LinkProperties</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onBlockedStatusChanged</span><span class="token">(</span><span class="token" style="color: #6f42c1;">network</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Network</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">blocked</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">Boolean</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle blocked status of a network change</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onCapabilitiesChanged</span><span class="token">(</span><span class="token" style="color: #6f42c1;">network</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Network</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">networkCapabilities</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">NetworkCapabilities</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle network capabilities change</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-445"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-443">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-444'
	>
	After defining a callback we just needed to call <em>connectivityManager.requestNetwork()</em>, passing in the request and the previously defined callback.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-448"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-446">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-447'
	>
	A native dialog would pop up showing the available access points that meet the parameters passed to the specifier object. In the following picture there is a dialog showing one of our cameras named “BlackVue HAK 1613”.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-451"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-449"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-450">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2021/07/hak-camera-integration-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="248"
															width="716"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-454"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-452">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-453'
	>
	Clean up the request</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-457"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-455">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-456'
	>
	In case the connection is lost or not found we needed to unregister the request by calling:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-460"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-458">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-459'
	>
	<code>connectivityManager.unregisterNetworkCallback(networkCallback)</code></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-463"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-461">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-462'
	>
	Camera – Application communication</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-466"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-464">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-465'
	>
	With the connection successfully established, let’s dive deeper into the implementation of camera communication.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-469"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-467">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-468'
	>
	We have two separate clients communicating with the camera in the application. The first one is a TCP socket used for commands and simple data correspondence. The second one is an HTTP connection client that transfers the camera’s live feed to the application.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-472"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-470">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-471'
	>
	Callback and propagating to the caller</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-475"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-473">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-474'
	>
	Before moving on to the network request callback, we needed a utility interface to propagate connection events to the corresponding view components. Every view component requiring a connection with the camera would be implementing this interface.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-477"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">WifiConnectionListener</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * Called after a connection has been established successfully.
</span></span><span class="line"><span class="token" style="color: #6a737d;">    </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onConnectionEstablished</span><span class="token">(</span><span class="token" style="color: #6f42c1;">ssid</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">String</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * Called if a connection attempt failed.
</span></span><span class="line"><span class="token" style="color: #6a737d;">    </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onConnectionFailed</span><span class="token">(</span><span class="token" style="color: #6f42c1;">ssid</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">String</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * Called when disconnected from a Wi-Fi network at a point in time after being connected to it.
</span></span><span class="line"><span class="token" style="color: #6a737d;">    </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onDisconnected</span><span class="token">(</span><span class="token" style="color: #6f42c1;">ssid</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">String</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * Called when the connection attempt is cancelled using WifiConnectionController.
</span></span><span class="line"><span class="token" style="color: #6a737d;">    </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onCancelled</span><span class="token">(</span><span class="token" style="color: #6f42c1;">ssid</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">String</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-480"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-478">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-479'
	>
	In the network callback for requesting a connection, we handled the outcomes of that request:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-482"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">var</span><span class="token"> </span><span class="token" style="color: #005cc5;">cancelled</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">var</span><span class="token"> </span><span class="token" style="color: #005cc5;">networkWithTargetSsidFound</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onAvailable</span><span class="token">(</span><span class="token" style="color: #6f42c1;">network</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Network</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">super</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">onAvailable</span><span class="token">(</span><span class="token" style="color: #005cc5;">network</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">cancelled</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6f42c1;">unregisterNetworkCallback</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">connectivityManager</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">bindProcessToNetwork</span><span class="token">(</span><span class="token" style="color: #005cc5;">network</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">networkWithTargetSsidFound</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">listener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">onConnectionEstablished</span><span class="token">(</span><span class="token" style="color: #005cc5;">ssid</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onLost</span><span class="token">(</span><span class="token" style="color: #6f42c1;">network</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Network</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #005cc5;">super</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">onLost</span><span class="token">(</span><span class="token" style="color: #005cc5;">network</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #6f42c1;">unregisterNetworkCallback</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #005cc5;">connectivityManager</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">bindProcessToNetwork</span><span class="token">(</span><span class="token" style="color: #005cc5;">null</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">     </span><span class="token" style="color: #005cc5;">listener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">onDisconnected</span><span class="token">(</span><span class="token" style="color: #005cc5;">ssid</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-485"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-483">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-484'
	>
	In addition to notifying the listener about the connection, we also bound the connection to the process. You might notice the canceled flag. We used it so that the user can cancel a connection attempt. The flag can be set from <em>WifiConnectionManager</em>, which is just a wrapper class for all the WiFi-related code. The manager is used on every screen that leverages the WiFi connection.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-488"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-486">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-487'
	>
	To account for connection time-out and other methods from <em>WifiConnectionListener</em>, here are other methods from <em>WifiConnectionManager</em>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-490"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">startResponseTimeoutCountdown</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">timeoutCountdownStarted</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">not</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">timeoutCountdownStarted</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6f42c1;">Handler</span><span class="token">(</span><span class="token" style="color: #005cc5;">Looper</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">getMainLooper</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">postDelayed</span><span class="token">(</span><span class="token" style="color: #d73a49;">::</span><span class="token" style="color: #005cc5;">onTimedOut</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">NETWORK_CALLBACK_TIMEOUT_MS</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onTimedOut</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">timeoutCountdownStarted</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">networkWithTargetSsidFound</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">not</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6f42c1;">unregisterNetworkCallback</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">cancelled</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">not</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">listener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">onConnectionFailed</span><span class="token">(</span><span class="token" style="color: #005cc5;">ssid</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">cancel</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">cancelled</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">listener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">onCancelled</span><span class="token">(</span><span class="token" style="color: #005cc5;">ssid</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-493"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-491">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-492'
	>
	This way we have successfully propagated the callback to the screen. The listener covers all the bad cases so we can show the appropriate message or try to connect again if we want to. Maybe we’ll want to try and reconnect if the camera disconnects in the middle of an exam. In that case, we just start the whole process again until we get that <em>onConnectionEstablished</em> callback again.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-496"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-494">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-495'
	>
	After establishing the connection and propagating the callback to the caller, there was still some work to do. We had to set up the clients to communicate with the camera over WiFi.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-499"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-497">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-498'
	>
	Setting up the clients</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-502"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-500">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-501'
	>
	Dashcam client</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-505"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-503">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-504'
	>
	The first client to set up was the dashcam command interface client. We decided to use a third-party library that provides a TCP socket implementation for Android called <a href="https://github.com/xuuhaoo/OkSocket"><em>OkSocket</em></a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-508"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-506">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-507'
	>
	The socket is set up in the following block of code:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-510"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-c github-light" data-language="c" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">connectionManager </span><span class="token" style="color: #d73a49;">=</span><span class="token"> OkSocket.</span><span class="token" style="color: #6f42c1;">open</span><span class="token">(</span><span class="token" style="color: #6f42c1;">ConnectionInfo</span><span class="token">(</span><span class="token">DashcamApiService.DASHCAM_IP</span><span class="token">,</span><span class="token"> DashcamApiService.DASHCAM_PORT</span><span class="token">)</span><span class="token">)</span><span class="token">.apply </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">option</span><span class="token">(</span><span class="token" style="color: #24292e;">OkSocketOptions</span><span class="token">.</span><span class="token" style="color: #6f42c1;">Builder</span><span class="token">(</span><span class="token">option</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #6f42c1;">setReaderProtocol</span><span class="token">(</span><span class="token">readerProtocol</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #6f42c1;">build</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">registerReceiver</span><span class="token">(</span><span class="token">socketActionAdapter</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">connect</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-513"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-511">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-512'
	>
	It creates the socket that connects to a given IP address and port. In our case, these were predefined by the camera manufacturer. The method returns a so-called <em>IConnectionManager</em> object that we could use to check the connection status.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-516"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-514">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-515'
	>
	The command’s requests and responses come as a predefined set of bytes. Not to go into details about what each of the bytes represents, those interested can take a look at the <em>IReader</em> and <em>DashcamCommand</em> implementations that serve as a custom mapper for headers and payload in each of our requests and responses.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-518"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">DATA_SIZE_START</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">8</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">DATA_SIZE_END</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">12</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">HEADER_LENGTH</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">12</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">readerProtocol</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">object</span><span class="token"> </span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">IReaderProtocol</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">getBodyLength</span><span class="token">(</span><span class="token" style="color: #6f42c1;">header</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">ByteArray</span><span class="token" style="color: #d73a49;">?</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">byteOrder</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">ByteOrder</span><span class="token" style="color: #d73a49;">?</span><span class="token">)</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">Int</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #005cc5;">header</span><span class="token" style="color: #d73a49;">?</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">let</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #6f42c1;">BigInteger</span><span class="token">(</span><span class="token" style="color: #005cc5;">header</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">copyOfRange</span><span class="token">(</span><span class="token" style="color: #005cc5;">DATA_SIZE_START</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">DATA_SIZE_END</span><span class="token">)</span><span class="token">)</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">toInt</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">}</span><span class="token"> </span><span class="token" style="color: #d73a49;">?:</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">
</span></span><span class="line"><span class="token">   }
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">getHeaderLength</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">HEADER_LENGTH</span><span class="token">
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">sealed</span><span class="token"> </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">DashcamCommand</span><span class="token">(
</span></span><span class="line"><span class="token">   val code: String
</span></span><span class="line"><span class="token">) : ISendable </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">override</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">parse</span><span class="token">(</span><span class="token">)</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">ByteArray</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Hex</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">stringToBytes</span><span class="token">(</span><span class="token" style="color: #005cc5;">code</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">GetSdCardInfo</span><span class="token">(val listener: (SdCardInfoResponse) -&gt; Unit) : DashcamCommand(&quot;00000001&quot; + &quot;07D0&quot; + &quot;000F&quot; + &quot;00000000&quot;)
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   class StartRecording(val listener: () -&gt; Unit) : DashcamCommand(&quot;00000001&quot; + &quot;07D0&quot; + &quot;0010&quot; + &quot;00000004&quot; + &quot;00000001&quot;)
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   object StopRecording : DashcamCommand(&quot;00000001&quot; + &quot;07D0&quot; + &quot;0010&quot; + &quot;00000004&quot; + &quot;00000000&quot;)
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   class UpdateUserString(userString: String, val listener: () -&gt; Unit) :
</span></span><span class="line"><span class="token">       DashcamCommand(
</span></span><span class="line"><span class="token">           &quot;00000001&quot; +
</span></span><span class="line"><span class="token">               &quot;07D0&quot; +
</span></span><span class="line"><span class="token">               &quot;0012&quot; +
</span></span><span class="line"><span class="token">               String.format(&quot;%08x&quot;, userString.length + 1) +
</span></span><span class="line"><span class="token">               Hex.bytesToStringUppercase(&quot; $userString&quot;.toByteArray())
</span></span><span class="line"><span class="token">       )
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-521"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-519">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-520'
	>
	With the socket and protocol set up, all we needed to do is make a client that would use these implementations to communicate with the camera. In the following section, we are going to go over the most important methods from <em>DashcamClient</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-523"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> DashcamClient.kt</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">commandQueue</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">mutableSetOf</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token" style="color: #005cc5;">DashcamCommand</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">var</span><span class="token"> </span><span class="token" style="color: #005cc5;">currentlyExecutingCommand</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">DashcamCommand</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">enqueueCommand</span><span class="token">(</span><span class="token" style="color: #6f42c1;">command</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">DashcamCommand</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">commandQueue</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">add</span><span class="token">(</span><span class="token" style="color: #005cc5;">command</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">connectionManager</span><span class="token" style="color: #d73a49;">?</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">isConnect</span><span class="token"> </span><span class="token" style="color: #d73a49;">==</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">) </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6f42c1;">executeNextCommand</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">executeNextCommand</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">connectionManager</span><span class="token" style="color: #d73a49;">?</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">isConnect</span><span class="token"> </span><span class="token" style="color: #d73a49;">==</span><span class="token"> </span><span class="token" style="color: #005cc5;">false</span><span class="token">) </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Socket disconnected. Aborting.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">currentlyExecutingCommand</span><span class="token"> </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Another command is currently executing. Aborting.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">commandQueue</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">isEmpty</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Command queue is empty. Aborting.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">commandQueue</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">first</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">let</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">currentlyExecutingCommand</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">it</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6f42c1;">sendCommand</span><span class="token">(</span><span class="token" style="color: #005cc5;">it</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-526"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-524">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-525'
	>
	The commands need to be executed one at a time. The client uses a command queue so that all the commands can be kept and executed sequentially. Before executing a command we have to check that the connection is alive and there is no other command executing at the time. After executing a command we use the following method to make sure everything is ready for the next one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-528"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">dequeueCommand</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">commandQueue</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">isEmpty</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Command queue is empty. Aborting.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">currentlyExecutingCommand</span><span class="token"> </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">commandQueue</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">remove</span><span class="token">(</span><span class="token" style="color: #005cc5;">currentlyExecutingCommand</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">currentlyExecutingCommand</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-531"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-529">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-530'
	>
	Finally, the following block of code shows how we send commands and receive responses from the camera.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-533"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">sendCommand</span><span class="token">(</span><span class="token" style="color: #6f42c1;">command</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">ISendable</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">connectionManager</span><span class="token" style="color: #d73a49;">?</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">send</span><span class="token">(</span><span class="token" style="color: #005cc5;">command</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">processResponse</span><span class="token">(</span><span class="token" style="color: #6f42c1;">data</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">OriginalData</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #6f42c1;">currentCommand</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">DashcamCommand</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">when</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">currentCommand</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">is</span><span class="token"> </span><span class="token" style="color: #005cc5;">DashcamCommand</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">GetSdCardInfo</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">val</span><span class="token"> </span><span class="token" style="color: #005cc5;">sdCardInfo</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #6f42c1;">parseSdCardInfo</span><span class="token">(</span><span class="token" style="color: #005cc5;">data</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">bodyBytes</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">currentCommand</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">listener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">invoke</span><span class="token">(</span><span class="token" style="color: #005cc5;">sdCardInfo</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">is</span><span class="token"> </span><span class="token" style="color: #005cc5;">DashcamCommand</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">StartRecording</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Recording started.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">currentCommand</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">listener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">invoke</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">is</span><span class="token"> </span><span class="token" style="color: #005cc5;">DashcamCommand</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">StopRecording</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Recording stopped.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">is</span><span class="token"> </span><span class="token" style="color: #005cc5;">DashcamCommand</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">UpdateUserString</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">currentCommand</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">listener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">invoke</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-536"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-534">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-535'
	>
	The socket connection adapter handles sending and receiving data from the camera. When the response arrives, it calls the <em>processResponse</em> method shown above. Every command takes a callback action in the constructor, invoked when the response arrives.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-539"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-537">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-538'
	>
	The <em>GetSdCardInfo</em> command takes an additional parameter in the callback, showing the SD card storage information.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-542"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-540">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-541'
	>
	The client and commands just described are enough to cover all of the camera operations during an exam. They work well even if the connection is lost during the exam because of the command queue that keeps all of the unexecuted commands.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-545"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-543">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-544'
	>
	When the connection is lost, the <em>WifiConnectionManager</em> attempts to re-establish connection and the commands are executed afterwards.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-548"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-546">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-547'
	>
	Camera feed streaming client</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-551"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-549">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-550'
	>
	The second client we made is called <em>LivestreamManager</em>. It transfers the stream from the camera to the app in real-time. There are 2 use-cases for this feature in our application:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-554"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-552">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-553'
	>
	<li>Camera preview screen – after connecting to a camera there is a screen with a live feed, so the examiner can make sure they are connected to the right camera. Since the exams usually start from the same place, there can be several cameras nearby and it’s possible to connect to the wrong one.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-557"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-555"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-556">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2021/07/hak-camera-integration-2-1400x840.webp				media='(max-width: 699px)'
				type=image/webp								height="840"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2021/07/hak-camera-integration-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="960"
															width="1600"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-560"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-558">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-559'
	>
	<li>Driving exam screen – we built in a small live feed window in the app drawer just in case the examiner wants to check the recording.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-563"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-561"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-562">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2021/01/hak-camera-integration-3-1400x840.webp				media='(max-width: 699px)'
				type=image/webp								height="840"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2021/01/hak-camera-integration-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="960"
															width="1600"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-566"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-564">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-565'
	>
	<em>LivestreamManager</em> features:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-569"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-567">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-568'
	>
	<li>Uses <em>WifiConnectionManager</em> to manage connection to the camera</li><li>IP Cam View – library to display stream from the camera endpoint</li><li>Observes the lifecycle of an activity or a fragment and resumes or pauses the streaming accordingly</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-572"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-570">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-571'
	>
	IP Cam View library offers a series of classes that help with subscribing to the stream and displaying it on screen. Streaming can be heavy on the device’s resources, so we added an observer on the screen lifecycle. That way we can stop streaming when the app is not in the foreground. <em>LivestreamManager</em> implements <em>LifecycleObserver</em>, which means it is tied to the lifecycle events of its host component and can react to them, given that the component implements <em>LifecycleOwner</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-575"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-573">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-574'
	>
	Similar to <em>DashcamClient</em>, <em>LivestreamManager</em> uses <em>WifiConnectionManager</em> to handle camera connection. If the camera disconnects, the app will try to re-establish the connection and notify <em>LivestreamManager</em> so it could resume streaming.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-578"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-576">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-577'
	>
	Here are some significant code blocks that show how <em>LivestreamManager</em> works.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-580"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">var</span><span class="token"> </span><span class="token" style="color: #005cc5;">streamSubscription</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Subscription</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">var</span><span class="token"> </span><span class="token" style="color: #005cc5;">stream</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">MjpegInputStream</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">init</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">dashcamWifiConnectionManager</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">addListener</span><span class="token">(</span><span class="token" style="color: #005cc5;">dashcamWifiConnectionListener</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">lifecycleOwner</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">lifecycle</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">addObserver</span><span class="token">(</span><span class="token" style="color: #005cc5;">this</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">@</span><span class="token" style="color: #6f42c1;">OnLifecycleEvent</span><span class="token">(</span><span class="token" style="color: #005cc5;">Lifecycle</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">Event</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">ON_RESUME</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">openLivestream</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">stream</span><span class="token"> </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Stream already opened. Aborting.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">streamSubscription</span><span class="token"> </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Livestream already requested. Aborting.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #6f42c1;">isLifecycleOwnerResumed</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">not</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Lifecycle owner not in resumed state. Aborting.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">dashcamWifiConnectionManager</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">isConnectedToDashcam</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">not</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Device not connected to dashcam. Aborting.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">streamSubscription</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">mjpeg</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">open</span><span class="token">(</span><span class="token" style="color: #005cc5;">DashcamApiService</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">DASHCAM_LIVESTREAM_ENDPOINT</span><span class="token">)</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">subscribe</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">stream</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Stream opened.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">streamSubscription</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #6f42c1;">isLifecycleOwnerResumed</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">               </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Lifecycle owner in resumed state.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">               </span><span class="token" style="color: #005cc5;">this</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">stream</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">stream</span><span class="token">
</span></span><span class="line"><span class="token">               </span><span class="token" style="color: #005cc5;">livestreamListener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">onLivestreamAvailable</span><span class="token">(</span><span class="token" style="color: #005cc5;">stream</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token">}</span><span class="token"> </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">               </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Lifecycle owner not in resumed state. Closing stream.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">               </span><span class="token" style="color: #6f42c1;">closeLivestream</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">throwable</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">log</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">onError called in startLivestream. Retrying.</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #005cc5;">streamSubscription</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">
</span></span><span class="line"><span class="token">           </span><span class="token" style="color: #6f42c1;">openLivestream</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">@</span><span class="token" style="color: #6f42c1;">OnLifecycleEvent</span><span class="token">(</span><span class="token" style="color: #005cc5;">Lifecycle</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">Event</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">ON_PAUSE</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">closeLivestream</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">stream</span><span class="token" style="color: #d73a49;">?</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">let</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">livestreamListener</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">onLivestreamUnavailable</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">it</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">close</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">stream</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">isLifecycleOwnerResumed</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">lifecycleOwner</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">lifecycle</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">currentState</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #6f42c1;">isAtLeast</span><span class="token">(</span><span class="token" style="color: #005cc5;">Lifecycle</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">State</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">RESUMED</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-583"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-581">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-582'
	>
	Stream events are sent to the activity or fragment through the <em>LivestreamListener</em> interface since LivestreamManager is not a UI component. The listener interface handles two possible cases, as can be seen in the following code block.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-585"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">interface</span><span class="token"> </span><span class="token" style="color: #6f42c1;">LivestreamListener</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onLivestreamAvailable</span><span class="token">(</span><span class="token" style="color: #6f42c1;">stream</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">MjpegInputStream</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #005cc5;">fun</span><span class="token"> </span><span class="token" style="color: #6f42c1;">onLivestreamUnavailable</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-588"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-586">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-587'
	>
	When the stream is connected and passed to the screen, it is passed as a source to <em>MjpegSurfaceView</em>, which is just a custom view for displaying a video stream. It is also a part of the library that we used to subscribe to the stream.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-591"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-589">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-590'
	>
	Key takeaways for technical implementation</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-594"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-592">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-593'
	>
	The sections above explain the technical side of what is needed for successfully recording a driving exam.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-597"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-595">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-596'
	>
	These are the key takeaways:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-600"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-598">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-599'
	>
	<li>WiFi Network Specifier API helps us to find the camera and connect.</li><li>Our app now handles WiFi connection like a pro, disconnects, timeouts, you name it.</li><li>We created a client to send commands to the camera and receive responses.</li><li>Displaying the camera’s live feed from over WiFi is wrapped nicely in the <em>LivestreamManager</em></li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-603"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-601">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-602'
	>
	It was a challenging but very educational journey. We implemented a feature that an average Android developer doesn’t see every day. Connecting an application to a camera was not a simple task, considering all the features, commands, streaming, etc. WiFi Network Specifier really saved us some work, because the old network scanning API was very difficult to work with.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-606"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-604">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-605'
	>
	We did have to move the minimum Android version to API level 29, but luckily for us this specific client uses only one tablet model and that one has an Android 10 update.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-609"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-607">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-608'
	>
	OkSocket and IP Cam View did their part in transferring the data between the application and camera and we took all the measures to keep the connection alive or reconnect if needed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-612"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-610">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-611'
	>
	Ensuring greater transparency</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-615"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-613">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-614'
	>
	Thanks to camera integration, the driving examination app now has an extra feature. Exams are recorded and documented through the app, so if there happens to be a complaint about an exam’s result, the examiner, the candidate, and the Croatian Automobile Club now have solid evidence for everything that happened during the exam.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-618"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-616">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-617'
	>
	Digitizing the driving evaluation process means less paperwork and more transparency – and hopefully many more great drivers on the road!</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/hak-camera-integration/">Camera Integration in the HAK Driving Exam App</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7924https://infinum.com/uploads/2020/11/dagger-hilt-0.webp</url>
				</image>
				<title>Stop Holding Dagger by the Blade: Use the Hilt</title>
				<link>https://infinum.com/blog/dagger-hilt/</link>
				<pubDate>Thu, 03 Dec 2020 17:23:00 +0000</pubDate>
				<dc:creator>Stjepan Banek</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/dagger-hilt/</guid>
				<description>
					<![CDATA[<p>Hilt will make your Dagger setup way more readable and much easier to maintain.</p>
<p>The post <a href="https://infinum.com/blog/dagger-hilt/">Stop Holding Dagger by the Blade: Use the Hilt</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-746"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-621">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-624"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-622">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-623'
	>
	Hilt is an Android library that reduces stress levels and stabilizes the blood pressure while using Dagger. If you’ve used Dagger before, we can agree that it has a steep learning curve, a long setup process and often hardly understandable errors.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-627"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-625">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-626'
	>
	In some ways, Hilt is a remedy for all three problems.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-630"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-628">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-629'
	>
	Getting ready to migrate from Dagger to Hilt</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-633"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-631">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-632'
	>
	It’s developed by Google and at the time of writing this blog post, it’s still in the alpha stage. So please check for the latest version before using it in production. It looks very promising! Judging by the official documentation page already being full of examples, we can expect a powerful and stable tool soon. Make sure to check the <a href="https://developer.android.com/training/dependency-injection/hilt-android">official documentation</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-636"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-634">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-635'
	>
	Hilt uses annotations to generate some parts of the dependency structure that you would normally have to write yourself. For example: <code>@HiltAndroidApp</code> will generate <code>ApplicationComponent</code>, <code>ApplicationModule</code>, <code>ActivityBuilderComponent</code> etc. This annotation is a starter pack solution for Dagger setup.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-639"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-637">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-638'
	>
	Since the topic of Hilt has already been covered in the documentation, this post will focus on migrating an example project from Dagger to Hilt, so I will assume that you are already familiar with Dagger.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-642"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-640">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-641'
	>
	Note this before we begin: It’s highly recommended that you do the migration all at once. Having both Hilt and Dagger (the old way) in your app will result in large overhead as Dagger and Hilt generate their dependency graphs separately. Also, each of your modules must be included in some Hilt component, or else the application won’t build.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-645"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-643">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-644'
	>
	Step 1: Add HiltAndroidApp annotation</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-648"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-646">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-647'
	>
	The application component is usually the entry point for Dagger dependency graph. Dependencies that are included here will be available through the whole application. This is an example of an application setup with Dagger.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-650"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Application Component class</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">@Component</span><span class="token">(
</span></span><span class="line"><span class="token">   modules </span><span class="token" style="color: #d73a49;">=</span><span class="token"> [
</span></span><span class="line"><span class="token">       AndroidSupportInjectionModule</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">,
</span></span><span class="line"><span class="token">       DatabaseModule</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">,
</span></span><span class="line"><span class="token">       FragmentBuilderModule</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">,
</span></span><span class="line"><span class="token">       ActivityBuilderModule</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">
</span></span><span class="line"><span class="token">   ]
</span></span><span class="line"><span class="token">)
</span></span><span class="line"><span class="token" style="color: #6f42c1;">@Singleton</span><span class="token">
</span></span><span class="line"><span class="token">interface AppComponent</span><span class="token">: </span><span class="token" style="color: #6f42c1;">AndroidInjector</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">ExampleApplication</span><span class="token">&gt; </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">@Component.Builder</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">interface Builder </span><span class="token">{
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #6f42c1;">@BindsInstance</span><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">fun application</span><span class="token">(application</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ExampleApplication</span><span class="token">)</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Builder</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">       </span><span class="token">fun build</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">AppComponent</span><span class="token">
</span></span><span class="line"><span class="token">   }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Application class</span><span class="token">
</span></span><span class="line"><span class="token">class ExampleApplication </span><span class="token">: </span><span class="token" style="color: #6f42c1;">DaggerApplication</span><span class="token">() {
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun applicationInjector</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">AndroidInjector</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">out</span><span class="token"> </span><span class="token" style="color: #6f42c1;">DaggerApplication</span><span class="token">&gt; </span><span class="token">{
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token"> DaggerAppComponent</span><span class="token">.builder</span><span class="token">()</span><span class="token">.application</span><span class="token">(</span><span class="token" style="color: #005cc5;">this</span><span class="token">)</span><span class="token">.build</span><span class="token">()
</span></span><span class="line"><span class="token">   }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-653"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-651">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-652'
	>
	Along with the Application component, it is common practice to also make an Application context module and Fragment and Activity builder modules for your application.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-655"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">@Module</span><span class="token">
</span></span><span class="line"><span class="token">class ApplicationModule </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">@Provides</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">@Singleton</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">fun provideApplicationContext</span><span class="token">(application</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ExampleApplication</span><span class="token">)</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Context</span><span class="token">   
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">=</span><span class="token"> application.applicationContext
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">@Module</span><span class="token">
</span></span><span class="line"><span class="token">interface FragmentBuilderModule </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * Add bind function for every fragment
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * with @ContributesAndroidInjector annotation
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * so that the fragment can be injected with dependencies
</span></span><span class="line"><span class="token" style="color: #6a737d;">    </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">@ContributesAndroidInjector</span><span class="token">(modules </span><span class="token" style="color: #d73a49;">=</span><span class="token"> [FriendsModule</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">])
</span></span><span class="line"><span class="token">   </span><span class="token">fun bindFriendsFragment</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">FriendsFragment</span><span class="token">
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-658"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-656">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-657'
	>
	Then you would make a module with specific dependencies for every fragment or activity and so on.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-663"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-659">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-660'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-661'
	>
	What if I told you that all of this boilerplate code I’ve just written can be replaced with just one annotation?</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-666"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-664">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-665'
	>
	Well that’s exactly what you can get by using Hilt. All you need to do is to place <code>@HiltAndroidApp</code> annotation above your application class and Hilt will do all the magic for you.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-668"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">@HiltAndroidApp</span><span class="token">
</span></span><span class="line"><span class="token">class ExampleApplication</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Application</span><span class="token">()
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-671"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-669">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-670'
	>
	Adding this annotation here will generate:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-674"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-672">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-673'
	>
	<li><code>ApplicationComponent</code></li><li><code>ApplicationContextModule</code> – It is included in the <code>ApplicationComponent</code> and it provides context of the application anywhere in the app through the predefined <code>@ApplicationContext</code> annotation.</li><li>Components for each of your application’s entry points: <code>ActivityBuilderComponent</code>, <code>FragmentBuilderComponent</code>, <code>ServiceBuilderComponent</code>, <code>ViewBuilderModule</code> etc.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-677"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-675">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-676'
	>
	Step 2: Annotate your entry points with @AndroidEntryPoint</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-680"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-678">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-679'
	>
	You might have noticed that you don’t have to use the <code>@ContributesAndroidInjector</code> annotations anymore. So how does the Hilt generated dependency graph know about your entry points? The answer is – <code>@AndroidEntryPoint</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-682"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">@AndroidEntryPoint</span><span class="token">
</span></span><span class="line"><span class="token">class MainActivity </span><span class="token">: </span><span class="token" style="color: #6f42c1;">AppCompatActivity</span><span class="token">() {
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">@Inject</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">lateinit</span><span class="token"> </span><span class="token">var </span><span class="token">analytics</span><span class="token">: </span><span class="token" style="color: #6f42c1;">AnalyticsProvider</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun onCreate</span><span class="token">(savedInstanceState</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Bundle</span><span class="token">?</span><span class="token">) {
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">super</span><span class="token">.onCreate</span><span class="token">(savedInstanceState)
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token">   }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-685"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-683">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-684'
	>
	Adding this annotation above any of the entry points will automatically add them to builder components generated by <code>@HiltAndroidApp</code>, making them injection ready. Hilt will also provide a predefined <code>@ActivityContext</code> annotation to inject activity context anywhere you need.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-688"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-686">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-687'
	>
	Everything available in the main application graph can now be injected to your entry points. If you need some specific dependencies for your entry point, you need to make a component that will only be available for that entry point. However, including your modules in <code>ApplicationComponent</code> or any of the generated components will work just as well.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-691"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-689">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-690'
	>
	<code>@AndroidEntryPoint</code> can be placed above:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-694"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--black block-bullet__bullet" data-id="es-692">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-693'
	>
	<code>Activity</code></p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-697"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--black block-bullet__bullet" data-id="es-695">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-696'
	>
	<code><code>Fragment</code></code></p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-700"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--black block-bullet__bullet" data-id="es-698">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-699'
	>
	<code><code>View</code></code></p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-703"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--black block-bullet__bullet" data-id="es-701">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-702'
	>
	<code><code>Service</code></code></p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-706"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--black block-bullet__bullet" data-id="es-704">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-16-text-roman js-typography bullet__paragraph'
	data-id='es-705'
	>
	<code><code>BroadcastReceiver</code></code></p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-709"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-707">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-708'
	>
	Step 3: Include your modules in the dependency graph with <code>@InstallIn</code></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-712"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-710">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-711'
	>
	Almost every project will have some modules that will provide some dependencies, such as network clients or databases. You can keep your existing modules. All you need to do is to add an <code>@InstallIn</code> annotation to each one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-714"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">@Module</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">@InstallIn</span><span class="token">(ApplicationComponent</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">)
</span></span><span class="line"><span class="token">class DatabaseModule </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">@Provides</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">fun database</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">MyDatabase</span><span class="token"> </span><span class="token">{
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token"> MyDatabaseBuilder</span><span class="token">.build</span><span class="token">()
</span></span><span class="line"><span class="token">   }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-717"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-715">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-716'
	>
	The<code>@InstallIn</code> annotation takes the component class as a parameter and you can add any of the generated components and even your own component in case you need to restrict access for some dependency. This must be done for every module, otherwise your app won’t build.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-720"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-718">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-719'
	>
	<code>@InstallIn</code> can also be used with <code>@EntryPoint</code> annotated classes. While <code>@AndroidEntryPoint</code> will automatically add your class to globally available components, with <code>@EntryPoint</code> you can define the component it will be installed in. This is a way of restricting some dependencies to specific screens or services.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-723"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-721">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-722'
	>
	Step 4 (Optional): Integrate Hilt with ViewModels</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-726"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-724">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-725'
	>
	We have already managed to reduce the boilerplate code amount significantly, but there is more of what you can do with it. Hilt offers a handy solution for <code>ViewModel</code> injection in your android apps. Firstly you need to add some additional dependencies to your app-level <code>build.gradle</code> file.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-728"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-groovy github-light" data-language="groovy" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">implementation &amp;#</span><span class="token" style="color: #005cc5;">8217</span><span class="token">;androidx</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">hilt</span><span class="token">:</span><span class="token">hilt</span><span class="token" style="color: #d73a49;">-</span><span class="token">lifecycle</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">viewmodel</span><span class="token">:</span><span class="token" style="color: #005cc5;">1.0</span><span class="token" style="color: #005cc5;">.0</span><span class="token" style="color: #d73a49;">-</span><span class="token">alpha01&amp;#</span><span class="token" style="color: #005cc5;">8217</span><span class="token">;
</span></span><span class="line"><span class="token">kapt &amp;#</span><span class="token" style="color: #005cc5;">8217</span><span class="token">;androidx</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">hilt</span><span class="token">:</span><span class="token">hilt</span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #005cc5;">compiler</span><span class="token">:</span><span class="token" style="color: #005cc5;">1.0</span><span class="token" style="color: #005cc5;">.0</span><span class="token" style="color: #d73a49;">-</span><span class="token">alpha01&amp;#</span><span class="token" style="color: #005cc5;">8217</span><span class="token">;
</span></span><span class="line"><span class="token"> 
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-731"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-729">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-730'
	>
	Then you need to add <code>@ViewModelInject</code> to your <code>ViewModel</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-733"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">class FriendsViewModel </span><span class="token" style="color: #6f42c1;">@ViewModelInject</span><span class="token"> </span><span class="token">constructor</span><span class="token">(
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">val </span><span class="token">repository</span><span class="token">: </span><span class="token" style="color: #6f42c1;">MyRepository</span><span class="token">
</span></span><span class="line"><span class="token">)</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ViewModel</span><span class="token"> </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">fun getFriendsList</span><span class="token">() {
</span></span><span class="line"><span class="token">       repository</span><span class="token">.getFriends</span><span class="token">()
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token">   }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-736"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-734">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-735'
	>
	And you are all set. Hilt will even go a step further and it will override the default <code>ViewModelProvider</code> factory with the injected <code>ViewModel</code> ‘s so you can use the <code>viewModels</code> property extension to get your <code>ViewModel</code> ‘s.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-738"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">@AndroidEntryPoint</span><span class="token">
</span></span><span class="line"><span class="token">class FriendsFragment </span><span class="token">: </span><span class="token" style="color: #6f42c1;">Fragment</span><span class="token">(</span><span class="token" style="color: #6f42c1;">R</span><span class="token">.</span><span class="token" style="color: #6f42c1;">layout</span><span class="token">.</span><span class="token" style="color: #6f42c1;">fragment_friends</span><span class="token">) </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token">val </span><span class="token">viewModel </span><span class="token" style="color: #d73a49;">by</span><span class="token"> </span><span class="token">viewModels</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">FriendsViewModel</span><span class="token">&gt;</span><span class="token">()
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun onViewCreated</span><span class="token">(view</span><span class="token">: </span><span class="token" style="color: #6f42c1;">View</span><span class="token">, savedInstanceState</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Bundle</span><span class="token">?</span><span class="token">) {
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">super</span><span class="token">.onViewCreated</span><span class="token">(view, savedInstanceState)
</span></span><span class="line"><span class="token">       viewModel</span><span class="token">.getFriendsList</span><span class="token">()
</span></span><span class="line"><span class="token">   }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token"> 
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-741"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-739">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-740'
	>
	A promising future</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-744"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-742">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-743'
	>
	Hopefully, by going through the steps you can reduce the setup time for dependency injection in your application and make it generally more readable. If you decide to migrate your application to Hilt, I would like to encourage you to keep watching for new updates and changes to Hilt. It is a promising library and plugin, and it could be bringing even more benefits in the future.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/dagger-hilt/">Stop Holding Dagger by the Blade: Use the Hilt</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>8094https://infinum.com/uploads/2020/04/viewbinding-the-new-standard-for-view-interaction-handling-in-android-0.webp</url>
				</image>
				<title>ViewBinding – the New Standard for View Interaction Handling in Android</title>
				<link>https://infinum.com/blog/viewbinding-the-new-standard-for-view-interaction-handling-in-android/</link>
				<pubDate>Mon, 06 Apr 2020 12:45:00 +0000</pubDate>
				<dc:creator>Stjepan Banek</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/viewbinding-the-new-standard-for-view-interaction-handling-in-android/</guid>
				<description>
					<![CDATA[<p>View Binding shines where many of its popular predecessors fail. Here's why it’s the new best practice in handling view interactions.</p>
<p>The post <a href="https://infinum.com/blog/viewbinding-the-new-standard-for-view-interaction-handling-in-android/">ViewBinding – the New Standard for View Interaction Handling in Android</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-872"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-747">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-750"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-748">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-749'
	>
	<a href="https://developer.android.com/topic/libraries/view-binding"><em>View Binding</em></a> is Google’s new method of referencing views. It generates a binding class for each of your <em>XML</em> layout files, and is used to interact with all views that have an assigned id value in a null-safe and type-safe way.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-753"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-751">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-752'
	>
	In comparison to the well-known methods such as <a href="https://kotlinlang.org/docs/tutorials/android-plugin.html"><em>Kotlin synthetics</em></a>, <a href="https://github.com/JakeWharton/butterknife"><em>Butterknife</em></a> and <a href="https://developer.android.com/reference/android/view/View#findViewById(int)"><em>findViewById</em></a>, it provides a safer and more concise way of handling view interactions inside your views. Before we compare them all side by side, let’s dive in <strong>the features of <em>View Binding</em></strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-756"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-754">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-755'
	>
	Advantages and disadvantages of <em>View Binding</em></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-759"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-757">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-758'
	>
	Some of the most relevant benefits of using <em>View Binding</em> are:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-762"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-760">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-761'
	>
	<li>Null safety – Properties in the generated class are non-null. In the case of multiple layout versions, e.g. <em>layout file</em> for different screen orientation or size, if some configuration contains an id that is not present in others, the generated property will be nullable.</li><li>Type safety – Binding properties will be correctly typed, even with custom views.</li><li>Interoperability – Generated classes are in Java and are optimized for Kotlin-Java interoperability.</li><li>Injection capability – Generated class can be injected in activity or fragment.</li><li>Speed – There are no impacts on build speed, as it doesn’t use an annotation processor. After the first build with <em>View Binding</em> is enabled, it will dynamically generate new properties. And if you add new view elements to your <em>XML</em>, there is no need to rebuild every time.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-765"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-763">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-764'
	>
	On the other hand, there are also some limitations:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-768"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-766">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-767'
	>
	<li>Large overhead possibility – It generates classes for each <em>XML</em> by default. This could be a large overhead if <em>View Binding</em> is not used in all classes.</li><li>Multiple binding class instances required – There is no clean way to handle single activity/fragments with multiple layout files, since every generated view binding class is bound to exactly one layout file and its configurations. This means that you have to use more than one binding class instance in your controller to handle more layouts.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-771"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-769">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-770'
	>
	Setup and usage example</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-774"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-772">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-773'
	>
	<em>View Binding</em> is available since Android Studio 3.6. It has to be enabled in your application module’s build.gradle.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-776"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-groovy github-light" data-language="groovy" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">android </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">     viewBinding</span><span class="token" style="color: #d73a49;">.</span><span class="token">enabled </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">     …
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-779"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-777">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-778'
	>
	This setting will enable generation of a binding class for every layout <em>XML</em> file in the module on the next build. However, if you would like to skip generating a class for specific layout, the following tag must be added in root element of that layout.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-781"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-xml github-light" data-language="xml" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">&lt;</span><span class="token" style="color: #22863a;">LinearLayout</span><span class="token">
</span></span><span class="line"><span class="token">        ...
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">tools</span><span class="token" style="color: #6f42c1;">:</span><span class="token" style="color: #6f42c1;">viewBindingIgnore</span><span class="token">=</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">true</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token">&gt;</span><span class="token">
</span></span><span class="line"><span class="token">        ...
</span></span><span class="line"><span class="token">&lt;/</span><span class="token" style="color: #22863a;">LinearLayout</span><span class="token">&gt;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-784"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-782">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-783'
	>
	The generated binding class is called ResultProfileBinding. This class has two fields: a TextView called name and a Button conveniently called, well, <em>button</em>. The ImageView in the layout has no ID, so there is no reference to it in the binding class.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-787"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-785">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-786'
	>
	If layout includes another layout file with <em>\</em> tag, a property will be generated, holding the included layout generated view binding. The included layout, same as all other generated views, must have an id tag.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-790"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-788">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-789'
	>
	The following code block shows the initialization and usage of the generated <em>View Binding</em> class in activity.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-792"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">ResultProfileActivity.kt</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">lateinit</span><span class="token"> </span><span class="token">var </span><span class="token">binding</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ResultProfileBinding</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun onCreate</span><span class="token">(savedInstanceState</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Bundle</span><span class="token">) {
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">super</span><span class="token">.onCreate</span><span class="token">(savedInstanceState)
</span></span><span class="line"><span class="token">    binding </span><span class="token" style="color: #d73a49;">=</span><span class="token"> ResultProfileBinding</span><span class="token">.inflate</span><span class="token">(layoutInflater)
</span></span><span class="line"><span class="token">    </span><span class="token">val </span><span class="token">view </span><span class="token" style="color: #d73a49;">=</span><span class="token"> binding.root
</span></span><span class="line"><span class="token">    </span><span class="token">setContentView</span><span class="token">(view)
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">…
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">And now you can use the binding in the following way</span><span class="token">
</span></span><span class="line"><span class="token">binding.name.text </span><span class="token" style="color: #d73a49;">=</span><span class="token"> viewModel.name
</span></span><span class="line"><span class="token">binding.button</span><span class="token">.setOnClickListener </span><span class="token">{ viewModel</span><span class="token">.userClicked</span><span class="token">() }
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-795"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-793">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-794'
	>
	In addition to the described way of initializing, <em>View Binding</em> can also be injected in activities and fragments, using one of the dependency injection libraries such as <em>Dagger</em>. This makes the “view controller” classes even more cohesive and independent from view initializing.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-798"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-796">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-797'
	>
	Before <em>View Binding</em>, there was no convenient way to achieve this. In order to inject the <em>View Binding</em>, you need to <em>@Provide</em> it in the module of your activity or fragment.<br>The following example shows <em>View Binding</em> injection in activity.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-800"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">@Module</span><span class="token">
</span></span><span class="line"><span class="token">class ViewBindingModule </span><span class="token">{
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Method providing the View Binding class</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">@Provides</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">fun viewBinding</span><span class="token">(activity</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ViewBindingActivity</span><span class="token">)</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ActivityViewBinding</span><span class="token">                    
</span></span><span class="line"><span class="token">   { 
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">return</span><span class="token"> ActivityViewBinding
</span></span><span class="line"><span class="token">                 </span><span class="token">.inflate</span><span class="token">(activity.layoutInflater)
</span></span><span class="line"><span class="token">   }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">This module makes sure the activity contributes itself to injection</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">@Module</span><span class="token">
</span></span><span class="line"><span class="token">interface ActivityModule </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">@ContributesAndroidInjector</span><span class="token">(modules </span><span class="token" style="color: #d73a49;">=</span><span class="token"> [ViewBindingModule</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">])
</span></span><span class="line"><span class="token">   </span><span class="token">fun viewBindingActivity</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ViewBindingActivity</span><span class="token">
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Activity</span><span class="token">
</span></span><span class="line"><span class="token">class ViewBindingActivity </span><span class="token">: </span><span class="token" style="color: #6f42c1;">DaggerAppCompatActivity</span><span class="token">() {
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">The injected View Binding class</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #6f42c1;">@Inject</span><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">lateinit</span><span class="token"> </span><span class="token">var </span><span class="token">binding</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ActivityViewBinding</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">   </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun onCreate</span><span class="token">(savedInstanceState</span><span class="token">: </span><span class="token" style="color: #6f42c1;">Bundle</span><span class="token">?</span><span class="token">) {
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #005cc5;">super</span><span class="token">.onCreate</span><span class="token">(savedInstanceState)
</span></span><span class="line"><span class="token">       </span><span class="token">setContentView</span><span class="token">(binding.root)
</span></span><span class="line"><span class="token">       </span><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-803"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-801">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-802'
	>
	Comparison with popular methods of handling view interaction</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-806"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-804">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-805'
	>
	In the following sections, I will try to make the case of why developers should start using <em>View Binding</em> by comparing it to other popular methods of handling view interaction: <strong><em>Kotlin synthetics</em>, <em>Butterknife</em></strong>, and the good old <strong><em>findViewById</em></strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-809"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-807">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-808'
	>
	The following is an example of referencing and setting a text in TextView using all four methods.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-811"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">findViewById</span><span class="token">
</span></span><span class="line"><span class="token">val </span><span class="token">textView</span><span class="token">: </span><span class="token" style="color: #6f42c1;">TextView</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token">textView </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">findViewById</span><span class="token">(R.id.textView) </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">This is not null or type safe</span><span class="token">
</span></span><span class="line"><span class="token">textView.text </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Hello</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Butterknife</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">@BindView</span><span class="token">(R.id.cardTextView)
</span></span><span class="line"><span class="token" style="color: #d73a49;">lateinit</span><span class="token"> </span><span class="token">var </span><span class="token">textView</span><span class="token">: </span><span class="token" style="color: #6f42c1;">TextView</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Initialized by passing the reference of activity/fragment</span><span class="token">
</span></span><span class="line"><span class="token">Butterknife</span><span class="token">.bind</span><span class="token">(</span><span class="token" style="color: #005cc5;">this</span><span class="token">)
</span></span><span class="line"><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token">textView.text </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Hello</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Not null safe</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Kotlin synthetics - Only supported in Kotlin classes</span><span class="token">
</span></span><span class="line"><span class="token">textView.text </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Hello</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">ViewBinding</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">lateinit</span><span class="token"> </span><span class="token">var </span><span class="token">binding</span><span class="token">: </span><span class="token" style="color: #6f42c1;">ActivityViewBinding</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token">ActivityViewBinding</span><span class="token">.inflate</span><span class="token">(layoutInflater)
</span></span><span class="line"><span class="token">setContentView</span><span class="token">(binding.root)
</span></span><span class="line"><span class="token" style="color: #d73a49;">..</span><span class="token">.
</span></span><span class="line"><span class="token">binding.textView.text </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Hello</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Completely null and type safe</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-814"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-812">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-813'
	>
	Syntax</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-817"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-815">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-816'
	>
	Using <em>View binding</em> requires using an instance of generated binding class, which means there is an additional variable in each view reference. On the other hand, you don’t have to create properties for views that you will be using in your activity, as is the case with <em>Butterknife</em> and <em>findViewById</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-820"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-818">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-819'
	>
	<em>Kotlin synthetics</em> definitely wins this one, because an extension is created for each view with id tag and it’s referenced just by the id value.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-823"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-821">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-822'
	>
	Code generation</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-826"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-824">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-825'
	>
	In terms of the generated code, <em>Butterknife</em> and <em>ViewBinding</em> behave very similarly. Each creates classes which bind views to properties based on the view’s id. The difference is that the Butterknife-generated class is based on the view controller class passed in the initialization, while <em>View Binding</em> is based on the <em>XML</em> layout file.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-829"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-827">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-828'
	>
	In the case of <em>Butterknife</em>, this can lead to nullability and safety issues as activities and fragments can inflate more than one different layout. <em>Kotlin synthetics</em> generate an extension. In order to reference the view, it must be inflated.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-832"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-830">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-831'
	>
	However, <em>Kotlin synthetics</em> have no way of checking if the right layout is inflated, so referencing a view that is not currently on the screen is allowed and leads to a null pointer exception.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-835"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-833">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-834'
	>
	<em>FindViewById</em> approach is easily the winner of this category, as it doesn’t generate any additional code, even though it does require some additional properties and is far from being safe.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-838"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-836">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-837'
	>
	Type and null safety</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-841"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-839">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-840'
	>
	<em>View Binding</em> is the only member of this group that ensures existence and the right type of every view for a given layout. This is one of the main advantages of <em>View Binding</em>, as it also works for different configurations of the layout. <em>View Binding</em> must be inflated with the <em>layoutInflater</em> from the screen controller, which means it ensures referencing the right layout.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-844"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-842">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-843'
	>
	<em>Butterknife</em> and <em>Kotlin synthetics</em> are not safe in terms of referencing the current layout and this can lead to null pointer exceptions. The same goes for <em>findViewById</em> as it is completely layout-ignorant and uses only the id to reference a view.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-846"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Example of Kotlin synthetics causing a null pointer exception</span><span class="token">
</span></span><span class="line"><span class="token">…
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">activity_two layout imported</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">import</span><span class="token"> </span><span class="token" style="color: #6f42c1;">kotlinx.android.synthetic.activity_two_synthetics.</span><span class="token" style="color: #005cc5;">*</span><span class="token" style="color: #6f42c1;"> </span><span class="token">
</span></span><span class="line"><span class="token">…
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Inflating the activity_one layout</span><span class="token">
</span></span><span class="line"><span class="token">setContentView</span><span class="token">(R.layout.activity_one)
</span></span><span class="line"><span class="token">…
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;">Referencing textView from another layout which is not inflated causes an exception</span><span class="token">
</span></span><span class="line"><span class="token">textView.text </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Some text</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> 
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-849"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-847">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-848'
	>
	Java and Kotlin interoperability</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-852"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-850">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-851'
	>
	<em>Kotlin synthetics</em> work only with Kotlin classes, which is a main disadvantage of this approach as there are still many Java Android developers and projects. Other mentioned approaches work with both Java and Kotlin.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-855"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-853">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-854'
	>
	It’s worth noting that <em>View Binding</em> generates Java performance optimized code and outperforms the rest of the group.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-858"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-856"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-857">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/04/viewbinding-the-new-standard-for-view-interaction-handling-in-android-1-1400x779.webp				media='(max-width: 699px)'
				type=image/webp								height="779"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/04/viewbinding-the-new-standard-for-view-interaction-handling-in-android-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="910"
															width="1636"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-861"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-859">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-860'
	>
	Finally, what should you use?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-864"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-862">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-863'
	>
	<em>View Binding</em> and <em>Butterknife</em> have a lot in common in terms of the idea behind the approach. However, <em>View Binding</em> addresses and successfully solves some of the issues of using <em>Butterknife</em>. That is probably why the official <a href="https://github.com/JakeWharton/butterknife">Butterknife Github</a> page recommends switching to <em>View Binding</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-867"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-865">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-866'
	>
	Even though it might seem that <em>Kotlin synthetics</em> offers a cleaner way of referencing views, the issues of null and type safety, as well as performance and interoperability issues should be reason enough to go with <em>View Binding</em> instead. As for the <em>findViewById</em> approach, it is legacy and it should stay that way considering all the disadvantages.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-870"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-868">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-869'
	>
	When in need of a safe way of interacting with your views, without having to worry about null and type issues, <em>View Binding</em> is definitely the way to go.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/viewbinding-the-new-standard-for-view-interaction-handling-in-android/">ViewBinding – the New Standard for View Interaction Handling in Android</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>