Amplify-android: Initialization in Activity#onCreate() may cause a crash or race condition

Created on 2 Jan 2020  路  5Comments  路  Source: aws-amplify/amplify-android

Initialization of Amplify in Activity#onCreate() may cause problems in the following scenarios though official documentation guides you to do so. Workaround is at the bottom of this issue.

  1. Start Activity and Amplify's initialization happens
Activity#onCreate()
  Amplify.addPlugin(AWSApiPlugin())
  Amplify.configure(applicationContext)
  1. Hit back button
Activity#onDestroy() called
  1. Re-launch the App again
Activity#onCreate() called again
  Amplify.addPlugin(AWSApiPlugin())
  Amplify.configure(applicationContext) // this throws AmplifyException

The reason this happens is because Amplify is a singleton object and keeps its state with static boolean configured and will not be subject to GC immediately after Activity#onDestroy() is called.
In this way, when Activity#onCreate() is called again, initialization is executed again, and a race condition occurs.
The official documentation catches the AmplifyException immediately, but because of this exception the configure per CATEGORIES is not done in Amplify#configure(), the app is obviously not in a good state.

The easiest workaround is to initialize in Application#onCreate().
This is the most realistic way. No race condition occurs because the lifetime of the Amplify object is tied to the life cycle of the Application.

// your custom application
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        try {
            Amplify.addPlugin(AWSApiPlugin())
            Amplify.configure(applicationContext)
        } catch (e: AmplifyException) {
            Log.e(TAG, e.message)
            throw RuntimeException(e)
        }
    }
}
// don't forget to add your app class in the manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="us.shiroyama.amplifyforandroid">
    <application
        android:name=".MyApplication" />
</manifest>
Bug Core

All 5 comments

Hi @shiroyama, thanks for raising this issue. I agree that Activity#onCreate(Bundle) is not a realistic hook from which to initialize Amplify, for some of the reasons you highlight.

Amplify was designed a process-wide singleton. In its current state, there is no method to "teardown" once configured. Its lifecycle mimics that of the Application.

I believe that either we should:

  1. Update the public documentation to suggest use of Application#onCreate(), or;
  2. Make clear that Activity#onCreate(Bundle) is only being used in the documentation for the purpose of simplifying the demo code.

Yeah I actually have the following language in the couple of documentation pages I wrote - perhaps we should adopt similar language throughout the rest of the documentation:

Add the following imports at the top of your MainActivity and code at the bottom of the onCreate method (ideally this would go in your Application class but this works for getting started quickly)

@jamesonwilliams @TrekSoft Why can't we stop throwing the exception if the configuration is set already?. Other SDKs are doing the same approach right?

if (! CONFIGURATION_LOCK.get()) {
   for (Category<? extends Plugin<?>> category : CATEGORIES.values()) {
    if (category.getPlugins().size() > 0) {
        CategoryConfiguration categoryConfiguration =
            configuration.forCategoryType(category.getCategoryType());
        category.configure(categoryConfiguration, context);
        beginInitialization(category, context);
    }
}
}

CONFIGURATION_LOCK.set(true);

Hi @Manuramv, to clarify, are you suggesting that we allow re-configuration of the categories? It ends up being a more complex topic than initially meets the eye. There is a good deal of discussion on this topic here: https://github.com/aws-amplify/amplify-android/issues/215

The documentation has been updated to suggest configuration of Amplify singleton in an Application class.

Was this page helpful?
0 / 5 - 0 ratings