Reputation: 2876
At startup of my application I would like to execute some initialization code.
I need to initialize:
As you know these are asynchronous tasks I need to perform.
What I currently have is my initialization code inside MainActivity.onCreate() with a callback method which will open CoreActivity. This works fine when I do a cold boot of the app.
The problem begins at the moment the app is moved to the background, Android can kill it to free memory. I force this behavior now by disallowing background processes under Developer options
.
So if I have ExampleActivity opened and I move the app to the background, Android tries to reinitialize ExampleActivity when I move it to the foreground. This means my app doesn't initialize properly because MainActivity.onCreate() is never executed.
So I thought I could move the initialiation code to Application.onCreate(). The problem I face here is that onCreate() completes execution and opens the ExampleActivity even while the initialization code is still running.
I noticed that sleeping the main thread inside Application.onCreate() is bad. Also having a while loop watching a isInitialized boolean never gets true and ends in a infinite loop.
How should I handle this situation?
I would like to do these steps
Upvotes: 4
Views: 3117
Reputation: 2411
I had a very close problem in my application for years. I.e. before starting almost any activity (or even onResume...) I need to make sure that my application is initialized. So far I had inserted a call to the synchronous initialization code to the onCreate method of many activities (in a case the initialization is done already, the call completes instantly, of course).
As gradually with an application grow the initialization takes more and more time, this started to cause ANRs sometimes in different activities, so I also came to the need to implement the asynchronous initialization on any activity start.
So, I recently implemented the below approach, which can be looked at / tested (see the GitHub project and, in particular, this class: MyContextHolder.java )
Insert a call to my statically defined application initialization code into onCreate method of every activity, which requires application to be initialized, passing the calling Activity instance (this) to the initialization code. Basically it looks like:
if (MyContextHolder.initializeThenRestartMe(this)) {
return;
}
a. If initialization is already done, return false instantly. Done.
b. If the initialization is needed, grab the Activity's launch parameters + the application's context so that the activity could be re-launched later. The simplest case: store the Activity's Intent. ( activity.getIntent() and activity.getApplicationContext() )
Finish the Activity, which is not even shown yet, with its .finish() method.
Optionally show some "Please wait..." activity to a User. (I didn't need this yet...)
Do application initialization in a background thread ( specialized AsyncTask ) using the applicationContext. See MyFutureContext.java )
On a completion re-launch the Activity using its stored parameters. E.g. using stored Intent and the Application's Context. Like this: applicationContext.startActivity(intent);
One useful tip: In order not to see blinking activities, which are being restarted, set default application's theme (in the Android Manifest) to a transparent one. Super!
The below style definition is from themes.xml file
<style name="Theme.Transparent" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
Upvotes: 3
Reputation: 6839
Why not add a Splash Activity which will do the INIT or atleast listen to the callback - INIT_DONE. On receiving such a callback, you can then start your desired activity.
By this you are achieving following things
Update : Why not check the INIT_State from Application.java file. If app INIT not done then load the base Activity or Splash and then the application will then work only in state where app init is done.
For this to achieve, you should have a baseActivity which will be extended by every other activity in the flow other than the splash activity. So, on every activity Resume event, you can check the INIT state and depending on it you can continue loading the activity or can redirect user to splash screen so that the INIT process completes and then user lands on other activities.
Also, for this you can also start AppInit process from splash screen. This will help monitor the control or else you can even use events for the same purpose to fit your design guidelines.
Upvotes: 1
Reputation: 14755
I see two alternatives:
If "MainActivity is killed by os"
If it is not ok that Async-stuff is done again:
Upvotes: 0