Making arguments work in Compose Navigation where there was XML

Jetpack Compose Navigation goes hand in hand with Jetpack Compose. The issue comes when you are coming from XML navigation. Passing arguments between screens is very easy in XML and by extending from Java.Serializable interface, everything was working like magic. But now, you open the Pandora’s box with Jetpack Compose and here is how you could fix it.

Continue reading “Making arguments work in Compose Navigation where there was XML”

How to tackle the R8 optimisation nightmare in a sane way?

Implementing R8 optimizations can always be a nightmare for the dev that has to do it. R8 is a compiler that works together with ProGuard to shrink, minify, and obfuscate your code. It can reduce significantly the APK size by removing classes that are not used at all. It checks the hierarchy of classes and once it sees a class is not being attached to anything, it removes it.

The above, of course, is a double-edged sword as in some cases, it can remove classes that you actually need like request/response classes and many others. But in a recent project, we got like 10 megabytes of reduced APK size (down from 30) which is a huge gain.

The problem comes when you want to tell R8 to keep certain classes that you need either deobfuscated or simply kept within your dex archive. So let’s see what the approach could be in such cases.

Continue reading “How to tackle the R8 optimisation nightmare in a sane way?”

Adding a custom lint rule to your Android project

We had one issue where people tend to create adapter classes inside fragments as properties and then forget to clear them out in onDestroyView. This actually creates a memory leak due to the adapter very often holding references to objects that were already destroyed. To prevent this from happening, we decided to create a custom lint rule that detects if you have an adapter field in your fragment class and warns you that it should be part of onCreateView instead.

Continue reading “Adding a custom lint rule to your Android project”

Throwing anything other than IOException in the OkHttp interceptor will crash your app

One thing to note, maybe you don’t know about it, is that OkHttp interceptors work with IOException. So if you decide to implement some kind of a retry mechanism – to refresh a token when you get a forbidden response code, to retry a request, or something else, keep in mind that if you throw anything different than IOException or a subclass of it, like InvalidStateException, your app will crash and the exception will not even reach the try-catch block of your code.

The reason for it can be found here -> https://github.com/square/retrofit/issues/3505

Downsides of Firebase Realtime DB for Android

There are a couple of downsides we figured out in our daily work with Firebase Realtime Database for Android and I would like to share them with you here. All of them revolve around using the provided SDK for Android. So let’s start.

Data listeners cannot be stopped

If you initiate a listener to observe some data like this one for example:

mDatabase.child("users").child(userId).get().addOnSuccessListener {
    Log.i("firebase", "Got value ${it.value}")
}.addOnFailureListener{
    Log.e("firebase", "Error getting data", it)
}

Then you may need to cancel it if your user leaves the screen where this data is presented. There is a cancel() method that you can call but unfortunately, this cancel method only removes the listener callback but does not cancel the operation going on in the background and lets it run until this completes.

Now imagine if you require a good big chunk of data for the screen and the user just does not want to wait because he has a 3G connection. You call cancel but the operation is still there in the background. You can verify logcat for that. What happens is that this operation still uses RAM memory that your app may need for something else and you can easily hit an OOM exception.

So for querying big datasets, it is best if you have a dedicated server that returns only the data that you need to work with.

Continue reading “Downsides of Firebase Realtime DB for Android”

The challenges of server-driven UI on Android

Server-driven UI is not a new concept. Neither for Android, iOS, or the web. It is quite popular in recent years, especially with the introduction of component-driven architectures such as Flux / Redux and others. Now three projects ahead with server-driven architecture in place, I want to share with you some of the challenges that we faced, and the different approaches to solving them. And I will be really happy if you share your experience too.

Continue reading “The challenges of server-driven UI on Android”

Local KtLint configuration for Android

KtLint & Detekt are tools that help us keep our code formatted in the same way and sometimes even help us spot errors before they are actually merged to master or develop.

Most of the CI integrations already include a detekt step before the unit tests are run. To avoid waiting for the CI, you can easily integrate ktlint as part of Git hooks. So every time when you decide to commit, Git hooks run and ktlint analyzes the committed files and prevents you from pushing until you fix your errors.

Continue reading “Local KtLint configuration for Android”

RecyclerView loses focus when scrolling fast … or how to use it on Android TV

We had a project where we were aiming to reuse the same codebase across mobile and TV. You have this care very often and there is this consideration of:

Should we use the Leanback Fragments?

The experienced Android TV developer

that is always ignored. We give the project a quick go and check how it works on the Android TV emulator and decide it is not worth the effort to work on TV specific codebase that may require additional devs to support it. And this is where hell breaks loose.

Continue reading “RecyclerView loses focus when scrolling fast … or how to use it on Android TV”