avatarElye - A One Eye Developer

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

4311

Abstract

ing around the modal.</li><li>Then update the <code>TextView</code> by referring to the modal using <code>@{myTextModal}</code></li></ol><h2 id="b366">The Code Side</h2><p id="85fc">Here, it is simplified without the need to access the View Item anymore.</p><p id="1081">But it will need to access the Modal in the XML, and also have a different way to inflate the layout.</p><div id="102a"><pre><span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> binding: ActivityMainBinding</pre></div><div id="6374"><pre><span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> { <span class="hljs-keyword">super</span>.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView( <span class="hljs-keyword">this</span>, R.layout.activity_main)

binding.myTextModal = getTextFromLogic()

}</pre></div><p id="502d">In short, it is moving the modal into the XML, which make the code doesn’t need to access the View Item anymore.</p><h1 id="5f1d">XML Communicate back to Code</h1><p id="2272">Sometimes other than having assign variable from the code to the XML, we need the XML to respond back.</p><p id="1aa5">To demonstrate that, I’m getting <a href="https://readmedium.com/glide-image-loader-the-basic-798db220bb44">the same design here</a> to illustrate this. The design is to provide some image URL to be loaded into the ImageView.</p><figure id="798a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*6dhZ3_qT6_KJKTjBqZRDuQ.png"><figcaption></figcaption></figure><h2 id="9715">In the XML</h2><p id="32dd">Here we define the usual Modal and the View</p><div id="0d5f"><pre><span class="language-xml"><span class="hljs-meta"><?xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"utf-8"</span>?></span> <span class="hljs-tag"><<span class="hljs-name">layout</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>></span>

<span class="hljs-tag">&lt;<span class="hljs-name">data</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">variable</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"imageUrl"</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"com.elyeproj.demoglide.ImageUrl"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">data</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ImageView</span>
    <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/my_image_view"</span>
    <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
    <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span>
    <span class="hljs-attr">android:src</span>=<span class="hljs-string">"@</span></span></span><span class="hljs-template-variable">{imageUrl}</span><span class="language-xml"><span class="hljs-tag"><span class="hljs-string">"</span> /&gt;</span>

<span class="hljs-tag"></<span class="hljs-name">layout</span>></span></span></pre></div><p id="91af">Notice we are sending the <code>ImageUrl</code> over to the <code>ImageView</code>.</p><p id="cf4d">So what is <code>ImageUrl</code>? It is just</p><div id="6f2f"><pre><span class="hljs-class"><span class="hljs-keyword">data</span> class <span class="hljs-type">ImageUrl</span>( <span class="hljs-title">val</span> <span class="hljs-title">fastLoadUrl</span>: <span class="hljs-type">String</span>, <span class="hljs-title">val</span> <span class="hljs-title">fullImageUrl</span>: <span class="hljs-type">String</span>, <span class="hljs-title">val</span> <span class="hljs-title">listener</span>: <span class="hljs-type">MyImageRequestListener</span>.<span class="hljs-type">Callback</span> )</span></pre></div><p id="f9f7">So how could that be an image loaded?</p><h2 id="15a2">In the code</h2><p id="8890">Before we look into that, we look into

Options

how it is setup</p><div id="b779"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">MainActivity</span> : <span class="hljs-type">AppCompatActivity</span>(), MyImageRequestListener.Callback { <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> binding: ActivityMainBinding

<span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onFailure</span><span class="hljs-params">(message: <span class="hljs-type">String</span>?)</span></span> {
    <span class="hljs-comment">// Do something on failure</span>
}

<span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onSuccess</span><span class="hljs-params">(dataSource: <span class="hljs-type">String</span>)</span></span> {
    <span class="hljs-comment">// Do something on success</span>
}

<span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
    <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(
        <span class="hljs-keyword">this</span>, R.layout.activity_main)

    binding.imageUrl = ImageUrl(
        <span class="hljs-string">"https://theFastLoadUrl~"</span>,
        <span class="hljs-string">"https://theFullImageUrl~"</span>,
        <span class="hljs-keyword">this</span>
    )
}

}</pre></div><p id="8c97">That’s the part that send <code>ImageUrl</code> over to the XML.</p><p id="873b">Upon receiving the <code>ImageURL</code>, the XML will be able to connect back to load the image using the below code</p><div id="1423"><pre>@BindingAdapter<span class="hljs-params">("android:src")</span> fun <span class="hljs-keyword">set</span>ImageUrl<span class="hljs-params">(view: ImageView, imageUrl: ImageUrl?)</span> { imageUrl?<span class="hljs-string">.let</span> { val requestOption = RequestOptions<span class="hljs-params">()</span> <span class="hljs-string">.placeholder</span><span class="hljs-params">(R.drawable.placeholder)</span><span class="hljs-string">.centerCrop</span><span class="hljs-params">()</span>

    Glide.with<span class="hljs-params">(view.context)</span><span class="hljs-string">.load</span><span class="hljs-params">(it.fullImageUrl)</span>
            <span class="hljs-string">.transition</span><span class="hljs-params">(
                DrawableTransitionOptions.withCrossFade()</span>)
            <span class="hljs-string">.thumbnail</span><span class="hljs-params">(Glide.with(view.context)</span>
                <span class="hljs-string">.load</span><span class="hljs-params">(it.fastLoadUrl)</span>
                <span class="hljs-string">.apply</span><span class="hljs-params">(requestOption)</span>)
            <span class="hljs-string">.apply</span><span class="hljs-params">(requestOption)</span>
            <span class="hljs-string">.listener</span><span class="hljs-params">(MyImageRequestListener(it.listener)</span>)
            <span class="hljs-string">.into</span><span class="hljs-params">(view)</span>
}

}</pre></div><p id="4561">Notice that it <code>@BindingAdaptor</code> to <code>android:src</code>, so that when the <code>ImageView</code> get data within the <code>android:src</code>, it will call this function and provide the <code>view</code> for use.</p><p id="ed86">Do note that the <code>setImageUrl</code> need to be a static function or a global function accessible by the XML directly.</p><p id="60aa">You can get the <a href="https://github.com/elye/demo_android_glide_basic_data_binding">code here</a>.</p><p id="5da8">While you notice there’s no direct need to access the View using ViewID from the code, we’ll need to add codes in the XML for the Data Binding to happens. This is one main limitation of Data Binding.</p><p id="60a5">With Jetpack Compose, such a need is not there anymore.</p></article></body>

Learning Android Development

Android Data-Binding Made Simple

Assigning Data and get UI Updated Automatically

Photo by Tamanna Rumee on Unsplash

Data Binding in Android has been introduced since 2015. However, due to it’s boilerplate, it is not as commonly used as one desired. Nonetheless, still good to know how it works.

To know how Data Binding is different from the conventional way, let’s look at the conventional way a little

Conventional View Update

We have an XML

<TextView
    android:id="@+id/text_id"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

And in the code, we’ll have to access to the text_id and update it.

val myTextModal = getTextFromLogic()
val textView = findViewById(R.id.text_id)
textView.text = myTextModal

Note here, we have myTextModal is instantiated in the code instead of XML.

Data Binding View Update

To enable DataBinding, first, we’ll need to turn it on using the below in the app’s build.gradle file.

buildFeatures {
    dataBinding = true
}

The XML side

Instead of instantiating the modal in the code, the modal is instantiated in the XML instead.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="myTextModal"
            type="String" />
    </data>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@{myTextModal}" />

</layout>

To do so, we’ll have to

  1. Define an outer layer layout over the entire XML code.
  2. Then followed by data wrapping around the modal.
  3. Then update the TextView by referring to the modal using @{myTextModal}

The Code Side

Here, it is simplified without the need to access the View Item anymore.

But it will need to access the Modal in the XML, and also have a different way to inflate the layout.

private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(
          this, R.layout.activity_main)

    binding.myTextModal = getTextFromLogic()
}

In short, it is moving the modal into the XML, which make the code doesn’t need to access the View Item anymore.

XML Communicate back to Code

Sometimes other than having assign variable from the code to the XML, we need the XML to respond back.

To demonstrate that, I’m getting the same design here to illustrate this. The design is to provide some image URL to be loaded into the ImageView.

In the XML

Here we define the usual Modal and the View

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="imageUrl"
            type="com.elyeproj.demoglide.ImageUrl" />
    </data>

    <ImageView
        android:id="@+id/my_image_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@{imageUrl}" />

</layout>

Notice we are sending the ImageUrl over to the ImageView.

So what is ImageUrl? It is just

data class ImageUrl(
    val fastLoadUrl: String, 
    val fullImageUrl: String, 
    val listener: MyImageRequestListener.Callback
)

So how could that be an image loaded?

In the code

Before we look into that, we look into how it is setup

class MainActivity : AppCompatActivity(), 
    MyImageRequestListener.Callback {
    private lateinit var binding: ActivityMainBinding

    override fun onFailure(message: String?) {
        // Do something on failure
    }

    override fun onSuccess(dataSource: String) {
        // Do something on success
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(
            this, R.layout.activity_main)

        binding.imageUrl = ImageUrl(
            "https://theFastLoadUrl~",
            "https://theFullImageUrl~",
            this
        )
    }
}

That’s the part that send ImageUrl over to the XML.

Upon receiving the ImageURL, the XML will be able to connect back to load the image using the below code

@BindingAdapter("android:src")
fun setImageUrl(view: ImageView, imageUrl: ImageUrl?) {
    imageUrl?.let {
                val requestOption = RequestOptions()
                .placeholder(R.drawable.placeholder).centerCrop()

        Glide.with(view.context).load(it.fullImageUrl)
                .transition(
                    DrawableTransitionOptions.withCrossFade())
                .thumbnail(Glide.with(view.context)
                    .load(it.fastLoadUrl)
                    .apply(requestOption))
                .apply(requestOption)
                .listener(MyImageRequestListener(it.listener))
                .into(view)
    }
}

Notice that it @BindingAdaptor to android:src, so that when the ImageView get data within the android:src, it will call this function and provide the view for use.

Do note that the setImageUrl need to be a static function or a global function accessible by the XML directly.

You can get the code here.

While you notice there’s no direct need to access the View using ViewID from the code, we’ll need to add codes in the XML for the Data Binding to happens. This is one main limitation of Data Binding.

With Jetpack Compose, such a need is not there anymore.

Android App Development
Mobile App Development
AndroidDev
Android
App Development
Recommended from ReadMedium