RoboGuice is a fantastic dependency injection framework for Android that wraps Google’s Guice DI library with a set of helper classes and default injections that can make an Android developer’s life much easier. Unfortunately, this comes at a cost. Guice was not designed with mobile devices in mind and instead targets servers where objects startup is long but once you’re up, responses need to be quick. Because of this, startup times for apps using RoboGuice can be noticably long in the best case and uncomfortably long if you’re not careful. Below are some tips and tricks I’ve used to help defer that startup cost and improve the experience for the user.
- Know your dependency tree
This may seem obvious, but know what your dependency tree looks like and avoid injecting expensive objects or objects that depend on them during start up. If you work on a large team, have someone (or everyone) become familiar with your dependency graph and consult with them when you’ve decided you need to inject that harmless, lightweight class.
- Avoid static injection like the plague
Static injection is almost always a bad choice. In 99% of cases, static injection is used to make something available to a static method, making that method unsafe. I could go on, but the biggest reason to avoid it is that static injection happens when the injector is first created. There is no way to delay it. If the object you’re statically injecting takes a long time to instantiate or its dependencies do, you’ll be increasing your injector creation by the time it takes to create it and all of its dependencies.
- Avoid too many or complex modules
Try not to put too much complex logic into your modules. For example, instead of putting if/else logic into your modules to turn on/off debug behavior, present debug or non-debug modules at build time. This reduces the overhead of the module execution portion of your injector creation.
- Create a development mode injector to avoid eager loading of all singletons
RoboGuice, by default, creates your injector in production mode. A production mode Guice injector will eagerly instantiate any class that you’ve annotated with @Singleton or bound in a singleton scope, regardless of whether or not you’ve explicitly declared it to be eagerly loaded. Weird, right? Well it turns out you can override this behavior to ensure that objects are only instantiated as you need them. If you’re using RoboGuice <2.0, you’ll need to override the createInjector() method on your RoboApplication. In the return statement, you can instead call
return Guice.createInjector(Stage.DEVELOPMENT, modules);
In RoboGuice 2.0+, you can simply call
before creating any RoboActivities or calling RoboGuice.getInjector() (typically from your application onCreate)
- Use a RoboSplashActivity as a last resort
If you can’t seem to get your start up time down to a reasonable limit, consider using a RoboSplashActivity before any of your RoboActivities are created. It is an easy way to throw creation of your injector and any other heavy lifting you have to do onto a background thread so you can get a splash screen or loading indicator up immediately. Simply override its doInBackground and startNextActivity methods to … do your heavy lifting in the background and … start the next activity when its done.
There’s probably more that could be done to further optimize start up of a RoboGuice-based application, but these 5 should give you much more control over the way you use RoboGuice.