This is a question we get a lot. And there’s no easy way to answer it.
Apple might have easy-to-use tools, but its closed ecosystem can be limiting.
Android might be more flexible, but it requires effort to keep your app stable.
The truth is that every platform has its unique challenges. What’s important is that you employ best practices and avoid key mistakes during development.
That’s why, in this article, we present some of the common blunders that every Android developer should avoid.
Table of Contents
Being unfamiliar with Android Studio’s capabilities
Android Studio is the official integrated development environment (IDE) and perhaps the most powerful tool in a developer’s arsenal.
That’s because it includes several features that can help you develop apps faster and more efficiently.
Thus, not knowing and harnessing Android Studio’s full capabilities can hinder your productivity.
One feature you should master is the Gradle build system. It’s a tool that automates many tasks needed to turn your code into an executable file, ready to be deployed to a user’s device.
For example, you can create several versions of your Android app, each with custom configurations.
This allows you to optimize the APK package to fit specific devices or Android OS versions.
Intents are one of the most powerful mechanisms in Android programming.
They provide a flexible way for different parts of your app to communicate with each other without being explicitly connected. This allows you to swap and reuse components rather easily.
However, it’s important that you use them properly since a wrong intent can jeopardize your app’s safety.
For example, you should always use an explicit intent when starting a Service.
This is because, in an explicit intent, you also specify the target component, thus ensuring that the service will only come from a known source.
In contrast, an implicit intent doesn’t specify the application or service that will fulfill the request. This means malicious programs could respond to it, potentially starting a cyberattack.
The bottom line: intents are an effective way to promote modularity in your Android app. Without them, you risk developing a monolithic app that’s harder to maintain.
Not using fragments
A fragment is a modular component representing a portion of your app’s UI.
It’s like a “mini activity” within your app’s main activity. It has its own lifecycle, layouts, UI elements, and logic.
Fragments can also communicate with each other, giving rich interaction options.
For instance, when a user taps a button on Fragment A, it can request Fragment B to load a web page.
Fragments are vital for creating self-contained UI elements that can be freely reused and rearranged as the situation demands.
This is especially vital for achieving adaptable, responsive UIs.
You can have a fragment for your app’s navigation bar and another for the main window. This allows your UI to adapt to a phone or tablet configuration without re-coding them.
Without fragments, building modular and scalable Android apps will be much harder. If you need a list component in multiple activities, you must code and update them separately.
This is time-consuming and error-prone. Fragments can simplify that process.
Blocking the main thread
The main thread is the master thread that initiates and handles everyother component in your app, like a main program that executes all the other mini-programs.
By nature, the main thread is responsible for many things.
But one mistake many developers make is to have the main thread handle everything in your app – even operations that take a long time to execute.
This will block the main thread and freeze your app while it waits for the operation to finish. As a result, your app becomes unresponsive.
To avoid this, offload some of the app logic to multiple worker (or background) threads.
This allows demanding operations to run in the background, thus freeing up your main thread for other tasks like rendering the UI or receiving user input.
Using background threads is especially critical for operations that involve external calls, such as retrieving data from a database.
That’s because factors beyond your control (latency and congestion) can prolong these operations.
However, it’s important to keep your background threads self-contained. They shouldn’t try to update anything in the main thread – including UI elements.
Attempting that is dangerous because worker threads aren’t aware of the state of your main thread.
For example, if a background thread tries to update a UI element that doesn’t exist, your app could crash.
Failing to utilize data binding
Data binding allows a direct connection between data sources and UI elements via a single XML declaration.
So, for example, if you need to change the image file that the UI component should load, you can change the XML in the layout file instead of editing it in the code itself.
If you don’t use data binding, you’ll need to update UI elements explicitly in the code. This means more manual view lookups and more boilerplate code.
In other words, you risk creating an app that’s clunky, hard to read, and difficult to maintain.
Your app could also become slower with multiple unnecessary UI updates and manual lookup operations.
Without data binding, your app is less stable. That’s because data binding expressions are validated during compile time, thus helping you catch errors and reducing critical app crashes.
Not taking advantage of Android libraries
Building everything from scratch – instead of using Android libraries – is one of the mistakes new Android developers make.
Because why waste time, effort, and money coding something when someone has already done that work for you?
Android libraries provide developers with hundreds of pre-built functions, from loading images to initiating network connections.
It can simplify coding work because you don’t need to build certain functionalities from scratch. This also reduces the amount of code, thus making your app run faster and easier to maintain.
For example, Glide is a library that loads and optimizes images by automatically applying down-sampling and caching.
It can help you create image-heavy apps that run efficiently – all with just a single line of code:
Managing the app’s network is another necessary but tedious task that nearly every Android developer needs to do.
Fortunately, you can use a variety of libraries to facilitate the process for you.
One example is Volley, a library that includes functions for managing network requests.
This can include request cache management, prioritization, and automatic scheduling of network requests. This helps eliminate boilerplate code used for making network calls.
Android libraries can also help with different testing and debugging tasks.
One example is Mockito, a library that helps you create fake objects for the purpose of testing.
This eliminates the need to configure certain classes to conform to a test method, which could get tedious quickly.
These examples are just a fraction of what Android libraries can do.
We suggest exploring them the next time you encounter a tedious task during Android development – chances are good there’s a quicker solution out there!
Poorly handling bitmaps
Handling bitmaps is one of the trickiest tasks for developers to get right because of how memory intensive it is.
Improper handling of this segment can lead to poor performance or even app crashes caused by insufficient memory.
Let’s say a user takes a photo using a 10-megapixel camera, roughly translating into 10 million individual pixels.
Assuming the app uses the default of 4 bytes per pixel, that image alone could use roughly 40 MB – a huge chunk of memory for a mobile app.
Fortunately, image libraries like Glide can help avoid this problem by optimizing images for you.
Aside from optimizing images, they also ensure you don’t have unused bitmaps hogging memory space.
Using deep view hierarchy
Android uses a view hierarchy when rendering the layout. That means you can nest UI objects under other UI objects, which is useful for complex layouts.
However, overdoing this can impact your app performance negatively.
That’s because every time the app updates a layout, it also does the same for all nested elements in that layout – even if there’s no real need to.
As a result, it takes more time to load your app UI. In some cases, it can even freeze entirely.
Thus, your goal should be to keep your layout hierarchy as horizontal as possible. That way, updating a UI element eliminates the loading time for other unaffected components.
An Applied Sciences graduate and a true connoisseur of tech, Ivan is a software developer with a genuine love for exploring new technologies. QAs love his code, and his fellow developers always value his input. For Ivan, there is no issue too small to talk over, and no problem that can’t be solved together.
When he is not coding, Ivan is usually hiking or playing football. His ideal workspace? Probably a cottage in the mountains, with a serious gaming setup and fast internet connection.