Starting a new native Android app in 2015
Last year I wrote MeasureMe a native Android application. I have just started a new project I find it interesting the difference in tools and techniques I am using only 18 months after MeasureMe.
At the time I identified four main areas that I addressed first.
- Logging
- Inversion of Control / Dependency Injection
- Unit Testing
- Automated Building
In 2014 I used eclipse and ant to control the build process, logging was handled by slf4j and logback, for dependency injection i used roboguice and UnitTesting was done on pure java classes using JUnit.
In 2015 I have made some changes. I now use AndroidStudio and Gradle to build the application. I still use JUnit to write unit tests however Google has made life much easier and there is now a mock android layer available. I also use RoboElectric to extend the reach of the tests. Logging has remains the same and I am very happy with slf4j and logback.
I have moved to Dagger2 for dependency injection. Last year I used RoboGuice and at the time it was a close call between it and Dagger1. In the end I chose RoboGuice largely because the syntax was more familiar and there appeared to be more support and examples for it.
One of the issues I had with Dagger was that injecting each class was a bit clunky, but as it turned out given that I needed to work with ActionBar activity and at the time RoboGuice did not support using the compatibility libraries so I needed to write the clunky code to inject the activities anyway.
I noticed that Google had forked the original Square implementation of dagger and appeared to be doing a lot of work on it. I liked the purely generated approach both for speed and debugging so I decided to switch. For comparison with the other two dependency injection mechanisms the fragment or activity class looks like this
public class RecommendationListFragment extends BaseFragment {
@Inject
ILoggerFactory logger;
protected ApplicationComponent getApplicationComponent(Activity activity) {
return ((AndroidApplication) activity.getApplication())
.getApplicationComponent();
}
protected boolean isInjected() {
return logger != null;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getApplicationComponent(getActivity()).inject(this);
}
@Override
public void onResume() {
super.onResume();
if (!isInjected()) {
getApplicationComponent(getActivity()).inject(this);
}
}
I dont remember having to write the onResume code for RoboGuice but it seems like a small detail. The IoC container looked like this
@Module
public class ApplicationModule {
private final AndroidApplication application;
public ApplicationModule(AndroidApplication application) {
this.application = application;
}
@Provides
@Singleton
Context provideApplicationContext() {
return this.application;
}
@Provides
@Singleton
ILoggerFactory provideLogger(SlfLoggerFactory loggerFactory) {
return loggerFactory;
}
}
The application sets up the container like this
public class AndroidApplication extends Application {
private ApplicationComponent applicationComponent;
final private Logger logger = LoggerFactory.getLogger(AndroidApplication.class);
@Override
public void onCreate() {
logger.warn("Application started");
super.onCreate();
this.applicationComponent = initialiseInjector();
logger.debug("Application IoC bound");
}
protected ApplicationComponent initialiseInjector() {
return DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
public ApplicationComponent getApplicationComponent() {
return this.applicationComponent;
}
Where the DaggerApplicationComponent is generated code.
So far I have been pleased with Dagger2 in the sense that it just works and I’ve not had any weird behaviour. I have also started to extend what I do with dependency injection, I have started using scoped containers with presenters and unit tests using a mocked container. I will cover this in another post.