Moving On Up (Or Down)

03 Apr 2019 | tags: android

I tweeted that this morning after rediscovering CMD+SHIFT+UP. I have known about this shortcut for a while, but I guess I haven’t had reason to use it until lately.

And then I remembered a variation of this shortcut that would literally “move things don’t care”.

This being IntelliJ, these actions work on more than just properties. They work for basically anything in your code that has a scope – individual lines, functions, classes even!

There are two main movement actions, move statement and move line. Depending on what you want to do, each of these have their own benefits.

Moving a statement means that the IDE will respect the context within which that particular element exists. In the case of a single line of code, this means maintaining its current scope. What this means exactly is – if a line is inside a function, using CMD+SHIFT+UP/DOWN will never move it out of the function.

To wit:


But this line wants to move to another function! It says so itself! This is when CMD+ALT+UP/DOWN comes in handy:


This shortcut is really handy when reordering or refactoring functions:


I leave it as an exercise for the reader to see how the shortcut behaves with classes. Get moving and stop copy-pasting! :dancers:


Bug Reports: A Story

20 Feb 2019 | tags: android

“This tool sucks :facepunch::rage::rage::rage::rage:

“Ugh WTF this is so stupid :poop::fire::fire::fire:

These are just some of the things I have heard developers say over the years whilst working on Android. Sometimes they are trying to figure something out and there is not enough documentation, other times they are trying to make their tools do something and it just won’t work. Oftentimes, it is because they are expecting something to happen and it does not.

I know it can be frustrating, I have been a dev for more than a 12 years now after all. But then again, no matter how much or how loudly you curse the Android gods, where does that get you? Does it fix the issue? Does it improve the situation? I do not think so.

So what should we do then?

My answer has, and always will be, “have you filed a bug for it?”

Android has its own dedicated issue tracker organised into several components. This page enumerates those components and have some very good tips on how and when to file a bug.

It is important to select the correct component because (1) it makes the relevant team aware of your issue, and (2) each component may have a template for reporting issues.


Android Studio component with template

When writing up a bug report, think of what you, as a developer, would find useful if it were you receiving the issue. “This app sucks” is way less helpful than “I have trouble logging in with my credentials that work on my computer”.

I try to be as helpful to the developer as much as I can because we both have the same end-goal: to fix a verified issue.

It might be time-consuming, but when the bug you reported gets fixed and other devs start to notice and benefit from it, it is very rewarding. :green_heart:

I might be totally wrong but I’d like to think my bug report helped nudge this along :sweat_smile:


Sometimes, my feature requests actually get built too! :dancer:

Do you want to get your issues fixed too?

The trick is to make the bug report as great as possible. Let’s take this bug for example. I encountered an issue whilst running “Remove Unused Resources” from Android Studio and wanted to report it.

To gather the relevant information about my machine, I opened Android Studio and then chose “About Android Studio”. I then clicked on the copy icon in the dialogue box that appeared; that copies into my clipboard almost all the information asked for by the template!


Click that!

I then provided a short overview of the reproduction steps; I try to follow the given-when-then pattern. Set the scene first to give the developers some context of what we are trying to achieve. In this case, I have provided a zip file of sample project that reproduces the error.

Next, I reported what I was trying to do and what happened as a result. If there are multiple steps that need to happen first, I enumerate them all in order. In this bug, I have also provided a screenshot so that the team can quickly verify that they have reproduced my error exactly as I see it.

And finally, I tried to provide as much as detail as possible. Were there scenarios where this does not happen?

It looks like Studio detects layouts inflated through the generated binding file’s .inflate() method as unused. Views inflated using DataBindingUtil are not removed. (From here)

If it is a feature request, what would I like to see as the end result? What are the benefits of fixing this issue?

If I am beginning data binding, “user defined types” might be unfamiliar. (From here)

Are there any workarounds that I am aware of?

Found another way to fix it. Remove the spaces before and after the arrow, as such: android:onClick="@{()->handlers.onSendNotificationClick()}" (From here)

When I found a use case that was missed by the initial fix, I provided another sample project.

Really, a sample project is like a picture. It paints a thousand words.

EDIT (20190221): I cannot believe I need to say this but I will say it anyway: BE NICE. No one wants to talk to a jerk.

A good bug report is like a good story.

It presents the characters, introduces conflict, and finally, a denouement.

Be a good storyteller and hold your audience captive. After all, it’s the stories that make this world much more fun and interesting. :relaxed:


Unwrapping Framework Binding Adapters

15 Feb 2019 | tags: android data binding

For the past year or so, my team has been all-in with data binding. And if you know me at all, it obviously makes me one happy duck!

Over time the team has moved from seeing data binding as a Butterknife replacement to utilising more data binding features. In fact, we have built an arsenal of @BindingAdapters already!

This is precisely what prompted me to look at what we have currently. And I noticed a curious thing. We have written some Binding Adapters that we did not really need.

For example, we have this one for listening to the IME Action button:

@BindingAdapter("onEditorActionClicked")
fun onEditorActionClicked(editText: EditText, editorActionListener: EditTextEditorActionListener) {
    editText.setOnEditorActionListener { _, actionId, _ ->
        editorActionListener.onEditorActionClicked(actionId)
        false
    }
}

Thing is, we did not really need to write this custom BindingAdapter because one such thing exists in the framework.

It is understandable though that we missed this, because documentation on these things is a bit hard to come by. Even if we look at the framework source code, someone who is not too familiar with data binding might find it a bit hard to parse.

So let me try to help a little bit.

Whenever we want to implement a BindingAdapter – especially if it is going to hook into an existing listener – the first step should be to look at the Binding Adapters implemented in the framework. There’s a whole bunch written for all sorts of widgets (that is, except for AndroidX SearchView, but that’s another story).

Since we want to work with the IME Action for an EditText, we should look at TextViewBindingAdapter.

At the top of the file, we see this annotation: @BindingMethod(type = TextView.class, attribute = "android:onEditorAction", method = "setOnEditorActionListener")

The documentation kind of glosses over what this means; but in a nutshell:

(Note: If you are interested in how the data binding library automagically sets the listeners and manages the interfaces, I highly suggest to checkout the generated binding file of your layout.)

Oooh notice how setOnEditorActionListener is the method we actually call in our own custom BindingAdapter! Looks like we are on to something!

Let’s try to use this attribute then:

<EditText
    android:id="@+id/sample_edit_action"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:imeOptions="actionSend"
    android:onEditorAction="@{() -> handlers.onEditorActionClicked()}"/>

(Note: If you are not familiar with the lambda syntax I am using here, this is called a “listener binding” and you can read all about it here.)

(Second note: Lint will tell you there is no such attribute. Lint lies!)

The next bit we have to do would be to tell our handlers what needs to happen when onEditorAction is called. For simplicity, let’s say we want to show a Toast when the user clicks on the Send button.

fun onEditorActionClicked() : Boolean {
    Toast.makeText(this, "Send was clicked!", Toast.LENGTH_LONG).show()
    return false
}

The implementation is fairly straightforward, but one thing is important though: make sure the implementation has the same exact return value type as the interface (otherwise data binding gets into a StackOverflowException)!

Now what if we actually need the KeyEvent or the ActionId? Let’s update our implementation to factor those in:

fun onEditorActionClicked(view: TextView, actionId: Int?, event: KeyEvent?) : Boolean {
    when(actionId) {
        EditorInfo.IME_ACTION_SEND -> {
            Toast.makeText(this, "Send was clicked!", Toast.LENGTH_LONG)
                    .show()
        }
    }
    return false
}

And let’s update our layout file as well:

<EditText
    android:id="@+id/sample_edit_action"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:imeOptions="actionSend"
    android:onEditorAction="@{(v, id, event) -> handlers.onEditorActionClicked(v, id, event)}"/>

And we can finally delete our custom BindingAdapter! :tada:

:exclamation: Remember as well that data binding by default looks for methods prefixed with set. This means that if we can call a setter programmatically, we do not have to make a BindingAdapter for it. Some examples are setEnabled(), setBackgroundColor(), etc.

So in summary:

Have fun binding!