In this post I would like to showcase a situation when a developer has an external library which is very slow when initializing. In this case, a developer probably doesn’t want to initialize this library on the main thread because it will freeze the application. Instead, a developer wants to load it in the background and propagate the result on the main thread.
First of all, if you already have some initialization stuff in your custom Application class, you might want to do a proper splash screen. It means that a splash screen should be shown simultaneously after clicking on the application icon. It can be easily achieved by setting the background of your
SplashActivity in a theme.
And in your
Usually, a splash screen is a logo, so this
@drawable/background_splash could be a
layer-list for example:
All credits to this implementation go here.
BTW, if you use
<vector> asset as a
src for your
bitmap, be aware of this bug. Unfortunately, there is no workaround for this, sorry. So in case of a splash screen you should use
png files for API levels <23.
Initializing the library
If this ‘long initialization’ library is needed only at splash screen to load some data, then we can define it in the
SplashModule, so we will be able to clear all the references to the library after using it.
Right now we cannot
@Inject this library anywhere because it will freeze our UI. Instead, we will create an
Observable which receives a
SplashLibrary instance but still not initialized because we pass a
Lazy<> instance of it.
Injecting the library
Finally, we are able to inject the
Observable<SplashLibrary> to our
There are still some pitfalls that one should be aware of:
- The possibility of library throwing an exception => we need to implement
- The possibility of user leaving/rotating the Activity before the library initializes. This possibility leads to memory leaks because our code references Activity in the callback.
Handling errors while initializing a heavy library
In order to address this issue, one can pass an
Observer instance to
subscribe() method. Pretty easy:
Handling memory leaks if the user leaves the Activity
In this example it’s not enough to just unsubscribe from the
Subscription because while the object is initializing, Subscription cannot free resources and that’s why we hold destroyed Activity in memory which causes a memory leak. This can be easily seen in the LogCat if one enables
StrictMode.enableDefaults(); in the
Application class. When rotating an Activity, StrictMode logs several instances of an Activity.
That’s why we need to free the activity referenced in the created
Observer. We can do that by creating a static class that implements
Observer<SplashActivity>, passing an Activity reference there and then clearing it in
onDestroy(). In this way, we can ensure that nothing was leaked.
Keeping in mind all these points, one can easily initialize a library, make a network request or do any heavy processing while showing a splash screen.
Thanks for reading! The source code is available here.
In the next post I’ll write about handling rotation while initializing a heavy library.comments powered by Disqus