Android Main Activity Initialization Is Not Safe

May 17, 2018

Why?

Assuming from MainActivity (the first activity launch when app start) we launch AnotherActivity, then the application when into background/idle (because we press home button) and the application got killed because of low memory. When we try to open the app again, Android will try to resume from AnotherActivity without launching MainActivity.

What’s the problem?

Ideally, we would do application wide initialization code at Application.onCreate. Sometimes it is not possible to do so.

For example, I build an app which prompt for user input password in MainActivity to create an crypto object to be used for subsequent encryption and decryption. Due to the security nature of the app, I cannot store the password on disk. When the app got killed while idling, I lost the user input password (or crypto object). If I am not aware that this scenario might happen and resume at AnotherActivity, I will get a null password (or ctypto object) which I didn’t handle.

How to solve this?

We need a mechanism to check if the initalization at MainActivity is executed properly. If it hasn’t, we should launch MainAcvity immediately.

Below is my singleton class for the checking.

object App {
    fun checkRestartMainActivity(context: AppCompatActivity): Boolean {
        if (CRYPTO_INSTANCE == null) { // check if initialization is done properly
            val intent = Intent(context, MainActivity::class.java)
            // clear all activty history/stack and return to MainActivity
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK;
            context.startActivity(intent)
            context.finish()
            return true
        }

        return false
    }
}

Put the above checking in all Activity.onCreate (except MainActivity).

class AnotherActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (App.checkRestartMainActivity(this)) {
            return
        }
    }
}

NOTE: If you are using lateinit and clean up object/connection at onDestroy, beware of bumping into UninitializedPropertyAccessException.

If you don’t want to create a singleton object, you can use companion object in MainActivity to check for initialization.

class MainActivity : AppCompatActivity() {
    companion object {
        val INITIALIZED: Boolean = false
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        INITIALIZED = true
    }
}
class AnotherActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (!MainActivity.INITIALIZED) {
            // launch MainActiviy
            return
        }
    }
}

References:

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.