I have been developing my own android apps for some time now.

During this time, the most valuable lesson I have learned is that not all devices are the same. Things you might expect to work fail on some devices. You might be using a method that doesn’t exist. Even though your code compiles just fine, it crashes on some devices.

This blog posts lists those things (those that I remember, at least) that have caused me trouble, so you know about and avoid them.

java.util.Objects

The Java version of some old android devices does have the class java.util.Objects , which was added in Java 7. So using the method

Objects.requireNonNull()

could lead to

Fatal Exception: java.lang.NoClassDefFoundError: java.util.Objects

Here is an error report from Firebase that proves this does actually happen:

Keep this in mind if you need to support older devices.

org.apache.commons.lang3 library

org.apache.commons.lang3.mutable.MutableBoolean is part of the Apache Commons Lang 3 library, a third-party library.

If you happen to include this library in your project, you might be unlucky and come across NoSuchMethodException on some devices.

How can this happen?

This has to do with the Zygote, a special android process. I won’t go into detail on what it is and how exactly it works (I am not an expert on this), but you can read this answer on stackoverlow.

Some device manufacturers bundle some Java libraries in the Zygote process. This causes all processes to include those libraries (including your own app), and even if your app has a newer version of the library, the one included by the manufacturer “wins”.

If the manufacturer has bundled the org.apache.commons.lang3 library and you do it as well, they might have bundled an older version where a method you might be using does not exist. Calling it will result in a NoSuchMethodException.

This has happened to me with MutableInt.decrementAndGet() , which was added in later releases of the library.

What can you do about it?

You cannot avoid this problem programmatically. A library which has been bundled by the manufacturer in the Zygote process will always override the version that you have included.

This might not be a satisfactory answer. You can just avoid using the org.apache.commons.lang3 library.

Here’s a question I asked on stackoverflow about this.

Usage of android.app.Fragment

You might have noticed that there are more than one Fragment classes.

android.app.Fragment (which has been deprecated) androidx.fragment.app.Fragment (or the older, android.support.v4.app.Fragment )



Why is that?

Initially, there was android.app.Fragment . As newer API releases were made, new functionality was added (e.g. new methods), which you only have access to from your code if you set the appropriate targetSdkVersion value for your project.

Here’s the catch though. Since you also specify a minSdkVersion version, for that version you have specified, the new functionality might not exist, but might be present for the targetSdkVersion.

Example

The onAttach(Context) method was added in API 23

method was added in targetSdkVersion is set to 28

minSdkVersion is set to 19 (KitKat)

In your fragment you override the onAttach(Context) method. The code compiles just fine.

What’s going to happen when your app runs on a device with KitKat (API 19), or any version less than 23?

The method just won’t be called! It’s like it was never there. If you code depends on fields that should be initialized in onAttach(Context) , it will probably crash with NullPointerException !

How to avoid it

Extend your fragments from androidx.fragment.app.Fragment , which is part of Android Jetpack. and avoid using android.app.Fragment , which has been deprecated.

Android Jetpack is a collection of libraries that greatly help with Android development. Pick what you want from it and include it in your project (you can include just parts of it). The great thing about Jetpack is that it evolves independently of the main android framework. When new features are available for a specific library in Jetpack that you use, you just need to update to the new version of that library.

If you cannot or do not want to use Android Jetpack, you also use the support v4 library, which has a Fragment that you can extend.

Here are some useful links:

Can Activity.getIntent() ever return null?

To pass data from an Activity to another Activity you use the putExtra() method of the Intent .

Intent intent = new Intent(this, UserActivity.class); intent.putExtra(UserActivity.USER_ID, userId); startActivity(intent);

So far so good.

Inside UserActivity you extract the user ID by calling:

getIntent().getStringExtra(USER_ID)

Since you make sure to always pass user ID through the Intent , it’s not possible that the user ID can be null . Or is it?

It CAN be null when Your application was updated from the market while it was in the memory and relaunched again after the update.

This event should be very rare, but since it’s possible, it will happen sometime.

See this answer on stackoverflow.

How to avoid it

Always save data that were passed to your activity inside the savedInstanceState, which is always persisted. Then, when your activity is restored ( savedInstanceState != null ), read the value from it.

private final String USER_ID = "user_id"; private String userId; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // When non-null, the activity is being recreated. Read from the saved state. if (savedInstanceState != null) { userId = savedInstanceState.getString(USER_ID); } else { // First time the activity opens, read from the extras passed to it. userId = getIntent().getStringExtra(USER_ID); } } protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putExtract(USER_ID, userID); }

One last thing!

If this guide has helped you, please consider to Buy me a coffee. Thanks! 🙂