2017: The year in review

09 Dec 2017 | Comments | tags: hello

Welp. Here we are. Another year is about to end.

For a lot of reasons several times throughout the year, I cannot wait for it to be over.

I welcomed the new year in the midst of a throng, freezing in the cold New York night, waiting for fireworks that never came. If there’s a more apt metaphor for the year that this has been, I do not know.

A lot happened this year, including moving this blog from its home of eight years, to shiny new Github pages. I crunched up some numbers and came up with this infographic (thanks Canva!):

That is probably more flying hours than I have ever flown before this year combined :sweat_smile:

A few more days of work and then I fly for the last time this year to Walt Disney World! Sooooo excited!

As a farewell, thank YOU for sticking with me throughout 2017! See you next year and have a great holidays!


Parsing Data Binding Errors

08 Dec 2017 | Comments | tags: android data binding

Learning something new is always fun and exciting. That is, until seemingly cryptic error messages start creeping up.

For the past year, I have been helping my teammates get more acquainted with data binding. One topic that frequently comes up is that if something goes wrong, it can be hard to figure out exactly why.

I have talked a lot about data binding, and the past couple of times that I did, I decided to include a section on a few of the errors I see most often.

1

This error means the layout file is using a variable (“user defined types”) called library, but it is has not been declared within the data element.

To fix this, make sure that any variables being used in the layout file have been declared. If they are, double check that there are no typos as well!

<data>
    <variable
        name="library"
        type="io.plaidapp.ui.AboutActivity.Library" />
</data>
<io.plaidapp.ui.widget.BaselineGridTextView
   android:id="@+id/library_description"
   android:text="@{library.description}" />

It turns out that I have reported this in the issue tracker, hopefully the team gets around to it soon! :smile:

2

If I remember correctly, during the early days of data binding, the BindingAdapter implementations would have the namespace included in the annotations. It did seem to ignore it, and at some point in the past year, this warning popped up.

It is not an error, but if you want to fix the warning, remove the namespace declaration and everything should be good to go!

@BindingAdapter({"imageUrl", "circleCrop"})
public static void setAvatar(ImageView imageView, String url, boolean isCircleCropped) {
   // Do stuff
}

3

Observable fields may be one of my most favourite things in data binding. If you are not familiar, I highly suggest reading up on them and trying them out.

To fix this warning, check that any Observable being used in a BindingAdapter uses the values (“contents”) directly.

As an example, say I have an ObservableBoolean called shouldLoadUserAvatar that I use in a layout file like this:

app:shouldLoadUserAvatar="@{dribbbleState.shouldLoadUserAvatar}"

In the BindingAdapter implementation, you can (and should) use a Boolean to get the value that we want:

@BindingAdapter({"userAvatar", "shouldLoadUserAvatar"})
public static void setPlayerCommentAvatar(ImageView imageView, String userAvatar, Boolean shouldLoadUserAvatar) {
   if (shouldLoadUserAvatar) {
       // Do stuff
   }
}

If there are more errors you see whilst using data binding, please share them (and how to fix them, if you can!) in the comments below!


Binding to the H(eight)

22 Nov 2017 | Comments | tags: android data binding

As would probably be obvious by now, I have been investing a lot of time in learning and using data binding.

Yesterday, we were trying to bind a view’s height and width to a value from a model. Directly using data binding did not work, and Googling for the issue says we have to do two things:

Remember that data binding strips out any data binding-related things in the XML. Without a default, the widget is left without a height and width. Hence the importance of including a default value.

<ImageView
    android:id="@+id/agent_photo"
    android:layout_width="@{entry.agentPhotoSize, default=@dimen/default_photo_size}"
    android:layout_height="@{entry.agentPhotoSize, default=@dimen/default_photo_size}" />

We set about creating the BindingAdapter as illustrated in the issue tracker. But running the code shows us that the height being set to the view is a massive value. The view seems to go on and on forever. Not good.

I was ready to give up and chalk it up to “Welp maybe RecyclerView does not like what we’re doing.” But I can’t just give up like that! But then suddenly… :bulb:

I don’t know how I missed it the first time, but I realised that we are passing in a dimension. Our BindingAdapter does work. But it is using the raw value of the dimension resource as the view’s height. Duh. Resolving the resource to the actual value makes us all happy again.

@BindingAdapter({"android:layout_height"})
public static void setAgencyBrandingHeight(View view, @DimenRes int height) {
    ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
    layoutParams.height = view.getContext().getResources().getDimensionPixelSize(height);
    view.setLayoutParams(layoutParams);
}

And then of course after figuring this out, I remembered that I already wrote about using resources. :no_good: