Andrew Bailey - Big Nerd Ranch Wed, 16 Nov 2022 21:27:01 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 Coming soon: Kotlin Programming: The Big Nerd Ranch Guide, Second Edition https://bignerdranch.com/blog/coming-soon-kotlin-programming-the-big-nerd-ranch-guide-second-edition/ https://bignerdranch.com/blog/coming-soon-kotlin-programming-the-big-nerd-ranch-guide-second-edition/#respond Tue, 14 Sep 2021 17:32:22 +0000 https://bignerdranch.com/?p=7726 Kotlin has been changing at a steady pace over the years, and more and more developers are choosing Kotlin as their language of choice. We're very excited to tell you all about the second edition of our Kotlin Programming book, which is fully updated for Kotlin 1.5 and IntelliJ 2021.2.

The post Coming soon: Kotlin Programming: The Big Nerd Ranch Guide, Second Edition appeared first on Big Nerd Ranch.

]]>

**Updated on 10/5/21** The Kindle version of the book is now available on Amazon! We’ve updated this post to include the latest information about the book’s availability.

 

Back in 2018, we released the first edition of our Kotlin Programming guide. Since then, a lot has changed in the world of Kotlin programming. The language has continued to evolve at a steady pace, and we’ve seen more and more developers adopt the language as time goes on. We’re also seeing many developers that are interested in new tools like Coroutines and Kotlin Multiplatform.

To help you adopt the language in your own projects and learn about these more advanced features, we’re excited to announce the second edition of our popular guide to Kotlin programming. Read on to learn about what’s changing in this latest installation!

Kotlin 1.5 & IntelliJ 2021.2

​Kotlin 1.5 introduced language features for unsigned numeric types and value classes (formerly called inline classes). There are also a number of quality of life improvements that have been introduced since our first Kotlin guide, like better type inference, when expressions with variable declarations, and improvements to the standard library. The second edition of our Kotlin programming guide incorporates these new features and will guide you through writing idiomatic Kotlin code. We’ve also updated our guide for the latest version of IntelliJ IDEA, which has also gotten some power-ups in its Kotlin editing features.

​Whether you’re coming to Kotlin for the first time or are brushing up your skillset, we think you’ll love these new features.​

Coroutines

​The kotlinx.coroutines library has changed drastically since we teased it in the first edition of our Kotlin programming guide. Right off the bat, Coroutines have graduated from experimental to stable and have become widely adopted in many production codebases.

​We’ve also seen the introduction and adoption of Channels and Flows, which build on top of Coroutines to allow parts of your application to communicate more easily. The book has three brand-new dedicated chapters for Coroutines, Channels, and Flows.

Kotlin Multiplatform

​Although many people think of Kotlin as a replacement for Java, that doesn’t paint the full picture. Kotlin is a multiplatform language and comes in three flavors: Kotlin/JVM, Kotlin/Native, and Kotlin/JS.

​The last part of the book will give you a taste of Kotlin Multiplatform. We will walk you through how to make a single project that compiles into a Java executable, a native macOS application, and a JavaScript script for use on the web.

​If you’ve been looking for a way to share code between platforms, give Kotlin Multiplatform a shot. We think you’ll be surprised at how much it can do for you. And if you want to learn more about Kotlin Multiplatform, may we point you in the direction of a few other blog posts?

On Virtual Shelves Now

​Whether you’re an Android developer who wants to use Google’s recommended programming language, a web developer who wants a concise alternative to Java, a developer looking to share code between apps on different platforms, a new programmer looking to learn a modern programming language, or anyone in between, Kotlin is a great choice. We hope that you pick up our Kotlin programming guide and enjoy working with the language as much as we do at Big Nerd Ranch.

The Kindle version for the second edition of Kotlin Programming: The Big Nerd Ranch Guide is available now from Amazon  and will be rolling out to other eBook retailers soon. Printed versions of the book are available for pre-order now and will ship in late October.

If you or your team would like the full Big Nerd Ranch experience, we offer instructor-led bootcamps where one of our expert instructors will teach you the Essentials of Kotlin. You can find more information on our books page. Also keep an eye on this blog and our social media for more updates from the Ranch.

Happy coding!

The post Coming soon: Kotlin Programming: The Big Nerd Ranch Guide, Second Edition appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/coming-soon-kotlin-programming-the-big-nerd-ranch-guide-second-edition/feed/ 0
[Updated] Two-Way Data Binding on Android: Observing Your View with XML https://bignerdranch.com/blog/two-way-data-binding-on-android-observing-your-view-with-xml/ https://bignerdranch.com/blog/two-way-data-binding-on-android-observing-your-view-with-xml/#respond Tue, 02 Feb 2021 15:00:53 +0000 https://nerdranchighq.wpengine.com/blog/two-way-data-binding-on-android-observing-your-view-with-xml/ Data Binding is a powerful library that's built around the idea of keeping your views up-to-date with your model. One of the lesser-known features is that it also lets you go backwards here. Using two-way Data Binding lets your model objects observe your views without the need to attach a listener to the view yourself.

The post [Updated] Two-Way Data Binding on Android: Observing Your View with XML appeared first on Big Nerd Ranch.

]]>
This post has been updated from the original 2017 version. At a high level, the new post: Converts all the information to reflect the move to Kotlin, adds clarification to separate Data Binding from modern MVVM conventions, and includes disambiguation on view model vs. androidx‘s ViewModel.

Android Two-Way Data Binding (Updated)

If you’ve used Data Binding in an Android app before, you’ll know how it makes your life easier by simplifying the problems you face when building your UI. Not only does it give you a type-safe, compile-time verified replacement to the standard findViewById method, but can also take care of all the heavy lifting in keeping your views up-to-date by seamlessly integrating your Java/Kotlin code with your XML layouts. It can also serve as the glue between the View and your View Model if you are using the MVVM architecture pattern on Android. If you haven’t tried out Data Binding yet, you can read more about it in one of our other blog posts, or on Google’s Data Binding documentation.

Data Binding is built around the idea of using data from a regular Java/Kotlin object to set attributes on your layouts, and that’s the extent to which most people use it. This is great because it allows you to define your view logic independently from the Android Framework (a boon for unit testing), but what if your view needs to set attributes on your object?

This is where two-way Data Binding comes in. Two-way Data Binding is a technique of binding your objects to your XML layouts so that the layout can send data to your binding object. This is compared to a “traditional” or “one-way” Data Binding setup, where data would only move from your binding object to the layout. You’ll see a suboptimal way of setting this up first, and then take a look at the built-in two-way binding (@={variable}) syntax.

The examples here are made with the MVVM architecture in mind, but they apply to any object that’s being attached to a view with Data Binding. Also bear in mind that these examples use View Models, but they are not using the Jetpack library of the same name. Here, a View Model is simply a class that holds view state. You can make it extend from the AndroidX ViewModel class if you are so inclined, but that goes beyond the scope of this blog post.

Simple Two-Way Data Binding with Listeners: A Quick and Dirty Approach

A quick way to achieve two-way Data Binding works in the same way as regular, “one-way” Data Binding. You probably wouldn’t want to use this in your app (as you’ll see later on), but instead as an intermediate step towards achieving your first two-way Data Binding setup. Consider that you’re making a password creation screen, and you want to show a password strength indicator as your user creates a password. To start, your layout looks like this:

password_view.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="viewModel"
            type="com.example.PasswordViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{viewModel.passwordQuality}"/>

    </LinearLayout>

</layout>

And your View Model looks like this:

PasswordViewModel.kt

class PasswordViewModel : BaseObservable() {

    var password = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.passwordQuality)
        }

    @get:Bindable
    val passwordQuality: String
        get() = when {
            password.isEmpty() -> "Enter a password"
            password == "password" -> "Very bad"
            password.length() < 6 -> "Short"
            else -> "Okay"
        }
}

For the View Model to do its job and calculate the passwordQuality, something needs to be setting the password field every time the user changes the text. One way to accomplish this is to bind a TextWatcher to the EditText using Data Binding — just like you can bind a String to an EditText. To start, you’ll add a new property to your View Model:

PasswordViewModel.kt

class PasswordViewModel : BaseObservable() {
    ...

    @get:Bindable
    val passwordTextWatcher = object : TextWatcher() {
        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
            // Do nothing.
        }

        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
            password = s.toString()
        }

        override fun afterTextChanged(s: Editable) {
            // Do nothing.
        }
    }
}

Then you can add the app:textChangedListener attribute in your layout’s XML file:

password_view.xml

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:textChangedListener="@{viewModel.passwordTextWatcher}" />

When you’re ready to try it out, you can go ahead and click the run button only to be greeted by a fairly long compiler warning. That’s because the Data Binding compiler plugin doesn’t know how to set the textChangedListener property of an EditText since there isn’t a method on EditText that’s called setTextChangedListener.

To fix this, you’ll have to create a BindingAdapter to tell the compiler how to set a TextWatcher on an EditText. To do this, you can create a new file with the following function, or add it to your existing binding adapters:

EditTextBindingAdapters.kt

@BindingAdapter("textChangedListener")
fun bindTextWatcher(editText: EditText, textWatcher: TextWatcher) {
    editText.addTextChangedWatcher(textWatcher)
}

Now when you launch this screen, you’ll see the password strength indicator updating to match what you type. This is very similar to how you would normally accomplish this using the MVC pattern – you’re creating a listener that updates the layout and attaching that listener to the EditText. The only difference here is that Data Binding is taking care of attaching the TextWatcher to the EditText instead of you doing it manually.

One difference between the MVC approach and the MVVM approach in this example is that you have to be very careful about not binding a second TextWatcher. If your View Model accidentally calls notifyPropertyChanged(BR.passwordTextWatcher) or notifyChange(), then you’ll add another TextWatcher. This will waste memory, and if your View Model does this too often, you’ll notice your layout’s performance decrease dramatically when the user types into the field because of the unnecessary work it’s doing.

Implementing two-way Data Binding in this way is very tedious and error-prone. It only pushes the problem of setting up this TextWatcher from your Activity or Fragment into your Data Binding variables. On top of that, it introduces another layer of complexity by forcing you to be mindful of all your listeners! Luckily, Data Binding has a built-in solution for this problem.

Two-Way Data Binding with Binding Adapters

Instead of having to create an XML attribute to bind a listener, you can take advantage of Data Binding’s built-in support for two-way bindings. Behind the scenes, the generated Binding class for your layout is still going to create a listener, but it will do all the heavy-lifting to maintain and keep track of this listener.

Go back to the original layout and View Model you started out with. Instead of adding a passwordTextWatcher property to your View Model, you’ll make sure that your password property is a mutable var as shown below. The ultimate goal here is to get Data Binding to call your setter. Make sure you also update your password property’s setter with a notifyPropertyChanged call as shown below:

PasswordViewModel.kt

class PasswordViewModel : BaseObservable() {

    @get:Bindable
    var password = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.passwordQuality)
            notifyPropertyChanged(BR.password)
        }

    ...
}

Next, update your EditText like this:

password_view.xml

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={viewModel.password}" />

Note the = in the Data Binding operator. This will cause the EditText to be populated with the value of password from the View Model as you’re used to, but the addition of the = will cause the password’s setter to be called whenever the text changes. This means that your PasswordViewModel’s password property will always contain the text in the EditText.

The next time you run your app, you’ll see that the password strength label still updates without you having to write a single BindingAdapter and without creating a listener yourself. Behind the scenes, your binding class is creating its own TextWatcher that functions similarly to the one that you defined manually and is binding and managing the TextWatcher itself.

Writing Your Own Inverse Binding Adapter

Just like how you have to write your own binding adapters to tell Data Binding how to call setters on views it doesn’t know about, you’ll sometimes have to the same thing for the views getters when you use two-way Data Binding.

Suppose that after a user has created a password, you want to show them legal information before they can start using the app. Since legal information tends to be very long, you decide to add a button that takes the user back up to the top of the page. When the user is already at the top of the screen, you also want to hide the button.

All of this can be accomplished with two-way Data Binding. You can start out by creating a basic layout as shown:

scrolling_legal_layout.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="viewModel"
            type="com.example.LegalViewModel" />
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

            <ScrollView
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="@string/lorem_ipsum" />

            </ScrollView>

            <android.support.design.widget.FloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/ic_scroll_to_top"
                android:layout_gravity="bottom|end" />

    </FrameLayout>

</layout>

Then you can create an empty View Model class:

LegalViewModel.kt

class LegalViewModel : BaseObservable() {

}

The first thing you’ll need to do is to add a scrollY property to your View Model. You can do this just like you would for a regular object:

LegalViewModel.kt

class LegalViewModel : BaseObservable() {

    @get:Bindable
    var scrollY = 0
        set(value) {
            field = value
            notifyPropertyChanged(BR.scrollY)
        }
}

While you’re in the View Model, you can also define the rest of the behavior for the scroll to top button. You can add the following property to determine the floating action button’s visibility:

class LegalViewModel : BaseObservable() {
    ...

    @Bindable
    val scrollToTopFabVisibility: Int
        get() = if (scrollY == 0) {
            View.GONE
        } else {
            View.VISIBLE
        }
    }
}

And another function to act as the click listener for the FloatingActionButton:

class LegalViewModel : BaseObservable() {
    ...

    fun scrollToTop() {
        scrollY = 0
    }
}

When you add the getScrollToTopFabVisibility() function, remember to update your scrollY property’s setter to dispatch the appropriate notifyPropertyChanged() call as shown below:

class LegalViewModel : BaseObservable() {

    @get:Bindable
    var scrollY = 0
        set(value) {
            field = value
            notifyPropertyChanged(BR.scrollY)
            notifyPropertyChanged(BR.scrollToTopFabVisibility)
        }

    ...
}

Next, it’s time to update the layout XML to tell the Data Binding compiler how to use your newly created functions. You can start out by updating the floating action button as shown:

scrolling_legal_layout.xml

android.support.design.widget.FloatingActionButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_scroll_to_top"
    android:layout_gravity="bottom|end"
    android:visibility="@{viewModel.scrollToTopFabVisibility}"
    android:onClick="@{() -> scrollToTop()}"/>

Then, it’s time to set up two-way Data Binding on the scroll position of your ScrollView. The syntax for this is the exact same as before, using the @={variable} syntax as shown below:

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:scrollY="@={viewModel.scrollY}">

If you try to compile the app right now, you’ll get a compiler error since the Data Binding compiler plugin doesn’t know how to get or observe the vertical scroll position – which is to say that the compiler doesn’t know how to read the scrollY value nor how to listen for updates to this value. To fix this, you’ll need to make an Inverse Binding Adapter. This inverse binding adapter will tell Data Binding how to get the current attribute of the view.

Start out by creating a new file for your inverse binding adapter (if you already have a binding adapters file you want to reuse, you can do all of these steps in that file instead if you prefer). Then you can go ahead and create the inverse binding adapter as shown:

ScrollViewBindingAdapters.kt

@InverseBindingAdapter(attribute = "scrollY")
fun getScrollY(scrollView: ScrollView): Int {
    return scrollView.scrollY
}

This gives Data Binding enough information to read the value from the view, but it still doesn’t know how to observe the value on the view. To fix this, you’ll need another binding adapter with a method signature that looks like the one shown below. Note that this example is using OnScrollChangeListener, which was added in Android Marshmallow (API 23).

ScrollViewBindingAdapters.kt

@BindingAdapter(
    value = ["scrollListener", "scrollYAttrChanged"],
    requireAll = false
)
fun setScrollListeners(
    scrollView: ScrollView,
    scrollListener: ScrollView.OnScrollChangeListener?,
    inverseBindingListener: InverseBindingListener?
)

There’s a lot going on here, so it’s a good idea to take a closer look before trying to implement this function, starting with the annotation. Those two strings labeled as value are the names of XML attributes that this Binding Adapter is responsible for. Having "scrollListener" lets you manually set an OnScrollChangeListener in your XML with the app:scrollListener attribute, should the need ever come up in the future.

The "scrollYAttrChanged" label is generated by the Data Binding compiler plugin. Every time you use two-way Data Binding, an internal attribute is created with the AttrChanged suffix. This is the attribute that Data Binding is going to look for when it goes to setup its event listener to update your View Model. Behind the scenes, Data Binding is going to generate code that uses this attribute to bind its observer.

The last thing in the annotation is the requireAll flag. This is simply telling the compiler that this function can be called without all of the parameters. For example, if your layout sets up two-way Data Binding on the vertical scroll position but doesn’t setup a scroll listener (or vice versa), then Data Binding will still call this function but it will pass in null for the scrollListener.

The first two parameters on this function should look pretty familiar. The ScrollView is the view whose scroll position will be observed, and the scrollListener is the optional listener that you can manually attach. The final parameter is a listener that Data Binding expects a callback on when a value changes. In a nutshell, this function’s responsibility will be to create a new OnScrollChangeListener that both wraps the scrollListener and calls the inverse binding listener. This implementation can be achieved like this:

@BindingAdapter(
    value = ["scrollListener", "scrollYAttrChanged"],
    requireAll = false
)
fun setScrollListeners(
    scrollView: ScrollView,
    scrollListener: ScrollView.OnScrollChangeListener?,
    inverseBindingListener: InverseBindingListener?
) {
    val newListener = if (inverseBindingListener == null) {
        scrollListener
    } else {
        object : ScrollView.OnScrollChangeListener() {
            override fun onScrollChange(v: View, scrollX: Int, scrollY: Int, oldX: Int, oldY: Int) {
                scrollListener?.onScrollChange(v, scrollX, scrollY, oldX, oldY)
                inverseBindingListener.onChange()
            }
        }
    }

    scrollView.setOnScrollChangeListener(newListener)
}

Every time that inverseBindingListener.onChange() is called, it signals to the the Binding class for your layout that the scroll position has changed. The binding class will then use the inverse binding adapter from before to get the current vertical scroll position of the view. This value will then be assigned to the scrollY property in your View Model.

If you run the app now and open this layout, you’ll see that everything is behaving exactly as intended – the FloatingActionButton is hidden by default and will appear once the user starts to scroll. This is great, but there’s one really important optimization you should make. Depending on which view you’re using and which attribute your View Model is subscribing to, setting up two-way Data Binding like this can cause an infinite loop. What’s worse is that this infinite loop won’t cause your app to crash or even freeze – it will silently consume CPU resources and drain the battery without any obvious problems.

The example with ScrollView doesn’t exhibit this behavior, but suppose that ScrollView implemented a setScrollY method like this:

public class ScrollView extends View {

    public void setScrollY(int y) {
        mScrollY = y;
        if (mScrollListener != null) {
            mScrollListener.onScrollChanged(this, mScrollX, mScrollY, mScrollX, mOldScrollY);
        }
    }

}


Every time that this ScrollView.setScrollY method is called, your callback is also triggered. Your callback is assigning the scrollY property in your LegalViewModel class from before. For reference, the scrollY setter is implemented like this:

class LegalViewModel : BaseObservable() {

    // Other properties omitted

    @get:Bindable
    var scrollY = 0
        set(value) {
            field = value
            notifyPropertyChanged(BR.scrollY)
            notifyPropertyChanged(BR.scrollToTopFabVisibility)
        }
    }
}

Because of the call to notifyPropertyChanged(BR.scrollY), your layout’s binding class is going to call ScrollView.setScrollY again, which causes this entire cycle to start all over. Because of the way Data Binding implements binding classes, though, it will wait until the next frame before calling setScrollY on the ScrollView.

The solution to this is very simple. In your LegalViewModel, update the scrollY setter to do nothing if the value didn’t change:

class LegalViewModel : BaseObservable() {

    // Other properties omitted

    @get:Bindable
    var scrollY = 0
        set(value) {
            if (field != value) {
                field = value
                notifyPropertyChanged(BR.scrollY)
                notifyPropertyChanged(BR.scrollToTopFabVisibility)
            }
        }
    }
}

It’s a good idea to do this on all the setters that you use with two-way Data Binding. View implementations can change over time so updating one of your libraries or using a different version of Android may cause this infinite loop behavior without any warnings. Adding this check is a simple way to guarantee that your two-way Data Binding won’t cause an infinite loop.

Conclusion

If you’re using MVVM or another similar architecture that takes advantage of Data Binding, then two-way Data Binding is a great way of getting information about your view into your View Models. If you’ve manually been binding listeners, then you should consider to the built-in technique for two-way Data Binding provided by the @={variable} syntax. It allows you to remove all references of view listeners from your View Models, which in turn makes your View Models more simple and easier to test.

If you’re not using MVVM, then two-way Data Binding may not be right for your app. Data Binding on its own works best when you have a model object that can directly be used by the view. If the layout XML has any logic, then suddenly you may find yourself debugging your layouts in addition to Java and Kotlin code. Adding two-way Data Binding without the right architecture can make debugging much more likely and difficult.

When you’re ready to set up two-way Data Binding on one of your layout attributes, there are just a couple of steps. To summarize:

  1. Setup one-way Data Binding for the attribute
  2. Add a setter to your model – make sure that this setter ignores the value if it hasn’t changed
  3. Add an = in your layout to use the @={variable} syntax
  4. Create an inverse binding adapter for the attribute if necessary

The post [Updated] Two-Way Data Binding on Android: Observing Your View with XML appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/two-way-data-binding-on-android-observing-your-view-with-xml/feed/ 0
The Quest for Q: What’s new in Android https://bignerdranch.com/blog/the-quest-for-q-whats-new-in-android/ https://bignerdranch.com/blog/the-quest-for-q-whats-new-in-android/#respond Mon, 13 May 2019 10:00:00 +0000 https://nerdranchighq.wpengine.com/blog/the-quest-for-q-whats-new-in-android/ Later this year, Android Q is going to appear on some of the 2.5 billion devices running on Android, so let's take a look at some of the highlights to look forward to.

The post The Quest for Q: What’s new in Android appeared first on Big Nerd Ranch.

]]>

Later this year, Android Q will appear on some of the 2.5 billion devices running on Android.

The announcement of Android Q isn’t brand new from Google I/O – there has been a public beta since March – but Google has given us more information about what’s in store in version 10.0 of the Android operating system and the Android platform as a whole.

New Features in Q

My personal favorite feature coming in Q is live captioning.

Google announced that they’ve developed a way to perform speech-to-text processing entirely on-device, without any audio ever leaving the device.

Users with hearing loss or who are in an environment where they cannot hear their phone will be able to enable live captions in Android Q (this feature is not yet enabled in Beta 3).

Any audio that contains speech that gets played on the device — no matter which app is playing it — will be transcribed to text and displayed on screen.

This works across the entire operating system, and app developers don’t need to do anything to support live captions in their app.

Another feature that users have been asking for a while is OS-level support for dark mode.

Dark mode lets developers change bright white backgrounds for darker backgrounds.

This not only increases usability at night where you might accidentally blind your users, but also helps save battery on many Android devices because OLED display technology uses less power for pixels on the display that are dark or completely black.

Many first-party apps from Google already support dark mode on existing versions of Android, but it is becoming a system-wide toggle in Q.

You can start designing for and implementing night mode right now.

There are also so many other subtle changes to things like permissions, notifications, and privacy that will most likely go unnoticed to many users, but are greatly improving the security and the overall user experience of the operating system.

For example, there are some new changes to notifications that bring AI-powered suggested actions to some notifications, and also changes to the prioritization and user-controls for how notifications are displayed.

Google has a blog post that describes all of these features in more detail.

What’s New for Developers

As an Android developer, I’m even more excited by what Google has announced for Android Jetpack and their developer tools.

One exciting change this year is Google’s push towards making Android a Kotlin-first platform.

This which means that if you’re using Kotlin in your app, you’ll get access to new and concise APIs that take advantage of Kotlin’s language features.

And if you’re just getting started with a new app, Google suggests that you should use Kotlin instead of Java.

This Kotlin-first paradigm manifests itself in a lot of Google’s Jetpack libraries.

For example, coroutines are now supported by Room, LiveData, and ViewModel — which were some of the first Android architecture components announced two years ago at I/O.

Google is also introducing new libraries that are designed for – and sometimes written in – Kotlin.

There are a number of new libraries that Google is working on, including View Bindings, CameraX, Benchmark, Security, and biggest of all, Jetpack Compose.

Jetpack Compose is a completely new UI toolkit built entirely in Kotlin.

It’s entirely decoupled from the existing UI APIs, and isn’t built off of View at all.

Instead, it provides an API reminiscent of Flutter, React, and Anko.

These APIs let you create a declarative UI that reactively responds to changes to your app’s state to update what’s on screen.

Here’s an example of what this might look like — the following code is from one of the slides at I/O, and lets you implement a list in 6 lines of code instead of breaking out a RecyclerView ( RecyclerView):

@Composable
fun NewsFeed(stories: LiveData<List<StoryData>>) {
    ScrollingList(stories.observe()) { story ->
        StoryWidget(story)
    }
}

Jetpack Compose is completely interoperable with existing layouts and views, so you’ll be able to migrate to it gradually — much like how you can gradually introduce Kotlin into a Java project.
The library still very early in development, and there is not yet an alpha version you can use yet.

In the meantime, you can see Jetpack Compose being developed in AOSP.

You can also read more about the new Jetpack libraries on Google’s blog.

These libraries have seen much more rapid changes than the APIs built into the OS itself recently, and that’s an extremely good thing for developers.

Even the brand new alpha versions of Jetpack libraries that have been announced or released this week at I/O support API levels as low as 14, which represents more than 99% of active devices on the Play Store.

You don’t need to wait for users to be on Q to use these new APIs like you would have in the past.

Google I/O marks a continuation of a trend from Google.

As Android is maturing, each version brings more polish and fewer overhauls than the last.

These changes will ultimately benefit users, but nothing coming in the Q release of Android is as drastic as features like runtime permissions, material design, or multi-window from previous versions.

Many new features that will impact users the most — like Google Lens, off-device machine learning, and updates to Google apps like the Assistant — are being distributed in Google Play or are Pixel-exclusives instead of ending up in the open-source portion of the Android operating system.

As a platform, however, Google is paying more attention to what developers are doing, and continue to empower them with libraries based on what developers are asking for.

These libraries are decoupling the APIs that developers are using from the framework itself, which helps fix device-specific bugs, and lets developers use more effective APIs much more quickly than in the past.

It’s a welcome ideology, and I’m looking forward to see where it takes us in the future.

The post The Quest for Q: What’s new in Android appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/the-quest-for-q-whats-new-in-android/feed/ 0
Room: Data Storage on Android for Everyone https://bignerdranch.com/blog/room-data-storage-on-android-for-everyone/ https://bignerdranch.com/blog/room-data-storage-on-android-for-everyone/#respond Tue, 04 Jul 2017 10:00:53 +0000 https://nerdranchighq.wpengine.com/blog/room-data-storage-on-android-for-everyone/ Room is a new way to save application data in your Android app announced at Google I/O this year. It's part of the new Android Architecture components, a group of libraries from Google that support an opinionated application architecture. Room is offered as a high-level, first-party alternative to Realm, ORMLite, GreenDao and many others.

The post Room: Data Storage on Android for Everyone appeared first on Big Nerd Ranch.

]]>

Room is a new way to save application data in your Android app announced at Google I/O this year.
It’s part of the new Android Architecture components, a group of libraries from Google that support an opinionated application architecture. Room is offered as a high-level, first-party alternative to Realm, ORMLite, GreenDao and many others.

Room is a high-level interface to the low-level SQLite bindings built into Android, which you can learn more about in Android’s documentation. It does most of its work at compile-time by generating a persistence API on top of the built-in SQLite API, so you don’t have to touch a single Cursor or ContentResolver. Room lets you use SQL where it’s most powerful, for query building, while taking care of schema definition and data manupulation for you.

Using Room

First, add Room to your project. After that, you’ll need to tell Room what your data looks like. Suppose you start with a simple model class that looks like this:

public class Person {
    String name;
    int age;
    String favoriteColor;
}

To tell Room about the Person class, you annotate the class with @Entity and the primary key with @PrimaryKey:

@Entity
public class Person {
    @PrimaryKey String name;
    int age;
    String favoriteColor;
}

With those two annotations, Room now knows how to make a table to store instances of Person. One thing to note when you’re setting up your models is that every field that’s stored in the database needs to either be public or have a getter and setter in the usual Java Beans style (e.g. getName() and setName(String name)).

Your Person class now has all the information Room needs to be able to create the tables, but you don’t have a way to actually add, query, or delete a Person’s data from the database.
That’s why you’ll have to make a data access object (DAO) next.
The DAO is going to give an interface into the database itself, and will take care of manipulating the stored Person data.

Here’s a simple DAO for the Person class from before:

@Dao
public interface PersonDao {
    
    // Adds a person to the database
    @Insert
    void insertAll(Person... people);
    
    // Removes a person from the database
    @Delete
    void delete(Person person);
    
    // Gets all people in the database
    @Query("SELECT * FROM person")
    List<Person> getAllPeople();
    
    // Gets all people in the database with a favorite color
    @Query("SELECT * FROM person WHERE favoriteColor LIKE :color")
    List<Person> getAllPeopleWithFavoriteColor(String color);
    
}

The first thing to notice is that PersonDao is an interface, not a class.
This interface is straightforward enough that Room could write the class for you, so that’s exactly what it does!
The other interesting detail is the SQL statements in the @Query() annotations.
The SQL statements tell Room what information you want to get out of the database, and they can be as simple or as complicated as you want.
They’re also validated at compile-time, so you can have confidence that your syntax is correct without having to run your app to see if you get a runtime exception.
So if you change the method signature of List<Person> getAllPeopleWithFavoriteColor(String color) to List<Person> getAllPeopleWithFavoriteColor(int color), Room will give you a compile error:

incompatible types: int cannot be converted to String

And if you make a typo in the SQL statement, like writing favoriteColors (plural) instead of favoriteColor (singular), Room will also give you a compiler error:

There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such column: favoriteColors)

You may notice that you can’t get an instance of the PersonDao because it’s an interface.
To be able to use your DAO classes, you’ll need to make a Database class.
Behind the scenes, this class will be responsible for maintaining the database itself and providing instances of the DAOs you declared before.

You can create your database class with just a couple of lines of code:

@Database(entities = {Person.class /*, AnotherEntityType.class, AThirdEntityType.class */}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract PersonDao getPersonDao();
}

This describes the structure of the database, but the database itself will live in a single file.
To get an AppDatabase instance saved in a file named populus-database, you’d write:

AppDatabase db = Room.databaseBuilder(getApplicationContext(),
        AppDatabase.class, "populus-database").build();

If you wanted to get all of the Person data that’s in the database, you could then write:

List<Person> everyone = db.getPersonDao().getAllPeople();

Keep in mind that RoomDatabase instances are expensive, so you’ll want to create just one and use it everywhere.
Dependency injection makes it easy to manage this instance.

Benefits of Using Room

Unlike most ORMs, Room uses an annotation processor to perform all of its data persistence magic.
This means that neither your application classes nor model classes need to extend from anything in Room, unlike many other ORMs including Realm and SugarORM.
As you saw when making mistakes with the @Query() annotations above, you also get compile-time validation of your database schema and SQL query statements, which can save you a lot of hassle compared to the runtime exceptions you’d get if you were using the native SQLite interface.

Room also allows you to observe changes to the data by integrating with both the Architecture Components’ LiveData API as well as RxJava 2.
This means that if you have a complicated schema where changes in the database need to appear in multiple places of your app, Room makes receiving change notifications seamless.
This powerful addition can be enabled with a one-line change in your DAO.
All that you have to do is change your @Query methods to return a LiveData or Observable object.

For example, this method:

@Query("SELECT * FROM person")
List<Person> getAllPeople();

becomes this:

@Query("SELECT * FROM person")
LiveData<List<Person>> /* or Observable<List<Person>> */ getAllPeople();

Room’s Biggest Limitation: Relationships

The biggest limitation of Room is that it will not handle relationships to other entity types for you automatically like some other ORMs will.
That means if you want to keep track of people’s pets like this:

@Entity
public class Person {
    @PrimaryKey String name;
    int age;
    String favoriteColor;
    List<Pet> pets;
}

@Entity
public class Pet {
    @PrimaryKey String name;
    String breed;
}

Then Room will give a compiler error since it doesn’t know how to store the relationship between a Person and its Pets:

Cannot figure out how to save this field into database. You can consider adding a type converter for it.

The compiler error suggests a type converter, which converts objects into primitives that can be directly stored in SQL.
Since List cannot be reduced into a primitive, you’ll need to do something different.
This is a one-to-many relationship, where one Person can have many Pets.
Room can’t model relationships like this, but it can handle the reverse relationship – each Pet has a single owner.
To model this, remove the pets field in Person, and add an ownerId field to the Pet class as shown:

@Entity
public class Person {
    @PrimaryKey String name;
    int age;
    String favoriteColor;
}

@Entity(foreignKeys = @ForeignKey(
            entity = Person.class,
            parentColumns = "name",
            childColumns = "ownerId"))
public class Pet {
    @PrimaryKey String name;
    String breed;
    String ownerId; // this ID points to a Person
}

This will cause Room to enforce a foreign key constraint between the entities.
Room won’t infer one-to-many and many-to-one relationships, but it gives you tools to express these relationships, fulfilling its promise as a high-level interface to SQLite.

To get all of the pets owned by a specific person, you can use a query that finds all pets with a given owner ID.
For example, you can add the following method to your DAO:

@Query("SELECT * FROM pet WHERE ownderId IS :ownerId")
List<Pet> getPetsForOwner(String ownerId);

If you want the pets field to stay in the Person model object, then there’s a few more steps.
The first is to tell Room to ignore the pets field – otherwise you’ll get the previously mentioned compiler error again.
You can do that by annotating the pets field with the @Ignore annotation like this:

@Entity
public class Person {
    @PrimaryKey String name;
    int age;
    String favoriteColor;
    @Ignore List<Pet> pets;
}

This tells Room not to read or write that field to and from the database.
This means that every time you get a Person from the DAO, the pets field will be set to null, so you’ll have to populate it yourself.
One way to do this is to have your Repository query for all Pets that a Person owns and set the pets field before passing a Person to the rest of your application.

Should You Use Room?

If you’ve already set up data persistence in your app and are happy with it, then you should keep it.
Every ORM and the native SQLite implementation are going to keep working just as they have before – Room is just another data persistence option.

If you’ve been using SQLite or are considering using it, though, you should absolutely try Room.
It has all the power you need to perform advanced queries while removing the need for you to write SQL statements to maintain the database yourself.

Alpha 3 of Room is available right now, but it’s very likely that the APIs will change before the final release, so you may want to avoid using it in a production app until then.
It’ll be available with the rest of the Architecture Components when they go stable in the coming months.

The post Room: Data Storage on Android for Everyone appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/room-data-storage-on-android-for-everyone/feed/ 0