Another couple of kotlin utils

I noticed a good number of claps on one of my previous posts about kotlin utils, that we using in our project. I admit I gathered my favorites (except those I described earlier here, here, and here).

In this post, I will scrape together another bunch of utils. But this time they will be smaller and simpler, yet still very handy, as for me.

Replacement of @BindView from ButterKnife

I will admit. I’m not a fan of code generation. That’s why we made a replacement of one code generation (from ButterKnife library) with another one (from kotlin itself) 😅

On a more serious note…

Before we started to use View Binding library from Android guys, we accessed views inside the custom layout directly. But using findViewById could be not the most convenient way, since in that case, we needed to separately assign found view to the property:

Moreover, in this piece of code, we will eagerly find and assign newly found view to the respective property. But maybe it will be used much later, thus, no need to spend time on finding it right now.

The obvious improvement for this code is the next snippet:

private val someTextView: TextView by lazy { findViewById(R.id.some_text_view) }

This is exactly what’s bindable utility method does:

fun <T : View> View.bindable(@IdRes id: Int): Lazy<T> = 
lazyUnsafe { findViewById<T>(id) }
fun <T> lazyUnsafe(initializer: () -> T): Lazy<T> =
lazy(LazyThreadSafetyMode.NONE, initializer)

Thus, we will have slightly more clean and concise:

Useful utils for context and view

Note that here we used some unknown form of inflate method. This is also the extension method. With we will also use another extension for context:

The first one we use all over across the project along with other extensions for System Services. The second one is the uses the first one to get access to the layout inflater and then inflate passed layoutRes.

Note that I also found the conversation in github regarding that extension method. But this conversation seems led nowhere because the repository was moved and the public github page is no longer for development. I checked the latest for today version 1.6.0 and the extension is still not here.

More handy dimension extensions for view

In the previous post I wrote how you can provide extensions that will allow you to write something like:

val p = view.padding.start

Sometimes you also need more power to work with the width/height of the views. This is especially felt in the situation you make custom view layouts. For example, a special layout that prevents view collisions with each other (you can check my article about that here).

From the previous article we remember that we have access to padding and margin of the view through the next handy extensions:

view.padding
view.margin

You can check more if you are interesting.

Now we can use them to create two pairs of small but useful extensions:

  • The first pair will get the full width/height of the view. Since view.height returns the height of the view itself. Sometimes it is useful to take the height of the view and additionally wrapping margins
  • The second pair will get the width/height of only the drawable part of the view. The mentioned view.height returns the height of the view with padding. But sometimes it is useful to know the height of the content area — an area without paddings.

Thus we have next extensions:

Coroutine properties — properties that can be suspended

Well, they are not quite properties we want. Moreover, it is worth mentioning that properties are designed initially in a way to not allow suspend keywords for a specific reason (here is a discussion about that).

But we created a simple wrapper, that helps us to work with properties, which we want to wrap for instance with a mutex when we set a new value.

Note: invoke is just a helper syntactic sugar method, that’s why it is an extension. We don’t want to give the ability to override it. Still, in your case, it may be useful (for test mocks or something else), so this is not a strict thing.

The interface is pretty straightforward and just mirrors a var property or a variable. But instead of using = to set a new value, we will use an explicit set method. By the way, it is infix method, so we will be able to write something like:

prop set 6

Now it is time to make a base implementation of the interface:

Just a simple implementation that will be a basis for the next decorations. For instance, we want to apply mutex on our property and change it in critical section:

The decoration is pretty straightforward. We take property that we already have and wrap set method with a mutex. By default each property has, it’s own mutex, but if you are sure you want to share mutex across properties then you can pass it to the constructor.

Next, is imitating of by observable:

Again, we just wrap our ‘setter’ with a callback that returns information about old & new values.

And don’t forget factory methods:

You can provide any decorations as you like. But what it gives you? It gives you the power to declaratively write the next thing:

This can be really useful if your service or any other class contains several properties and each of them should be ‘mutexed’ because of the coroutines environment and concurrent access/change

Afterwords

Unfortunately lately I write rarely. This is a tough topic but there are some reasons for that, including emotional burnout, lack of interesting thoughts to share, and the current situation with my job right now.

At the end of May, I left my last company, and right now I’m on the current of waiting. Waiting for better opportunities, interesting projects, and, thus, interesting problems. Which leads to better thoughts and better articles.

Yes, I could take something and “play” in my free time with that technology, but apparently, after years of mixing work and hobby, this is hard. So stay in touch. I hope I will bring something out soon 🤭

Love being creative to solve some problems with an simple and elegant ways