AI is here, and the best we can do now is take a look at it and not ignore it. I have been using Cursor with Claude for the past six months, both on personal and work projects of various sizes, and I can tell for sure that it handles some tasks with ease, while others are a huge struggle until you intervene and give the right direction. But even with that in mind, it still manages to save tons of hours of writing templates and sometimes makes me wonder whether my brain is working less effectively just because I can ask it to figure out a given problem for me. But here are the major problems that I experienced with it until now.
Continue reading “Cursor on Android: Where it struggles and how to make it useful”Fixing Android DataStore migration from a data object to a data class
I had to implement this migration for an object that was stored in DataStore using Protobuf and Kotlinx Serialisable on Android. The original object looked like this:
@Serializable
data class Assignment(val state: State)
@Serializable
sealed interface State {
@Serializable
data object Pending : State
// More implementations
}
The new object was supposed to look like this:
@Serializable
sealed interface State {
@Serializable
data class Pending(val id: String) : State
// More implementations
}
Continue reading “Fixing Android DataStore migration from a data object to a data class” Profiling and how to optimise your app startup and kill ANRs
Very often when building an app, you get taken away in the code architecture, building different components, and getting stuff done. You want features out, and very often you don’t have time to optimise stuff. Sadly, this is the way software development has gone in recent years, especially during the IT layoffs in the recent couple of years.
One thing that always gets missed and usually gets resolved is that your app just becomes slow. ANRs or Application Not Responding is an often thing that happens with mobile apps and people learn about it only when people actually start complaining from it. “Hey, we see a dialog that says Close app” is the most common thing you will hear from users. And this is when you realized they have already opened Pandora’s box for you.
I hope with this post to make you aware of how to identify such potential issues and try to fix them before they occur. Let’s go.
Continue reading “Profiling and how to optimise your app startup and kill ANRs”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”Observations of migrating an app from XML to Jetpack Compose
Jetpack Compose is the coolest kid on the block, but it has various different drawbacks that I at least notice when we did the migration of the app I was working on. And I wanted to share them in my blog with everyone, just in case you need to do the same thing in your app.
Continue reading “Observations of migrating an app from XML to Jetpack Compose”Why black-box tests could be a bad idea?
Blackbox tests are tests that are being done end-to-end. This means a UI automaton clicking on your mobile app that connects to the actual backend server – not prod, of course, but something close to staging. On Android specifically, you could use Espresso or UiAutomator to achieve those results.
Continue reading “Why black-box tests could be a bad idea?”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?”Android app fails to build with SSLHandshakeException
Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
Recently, I tried to build an Android project and it failed with the above error. It was a super nasty error to fix and I spent quite some time on it.
Continue reading “Android app fails to build with SSLHandshakeException”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