Dependency Injection for Android Development: Part Two

Mark Fricke Articles, Development Technologies & Tools, Java, Mobile, Tutorial 3 Comments

Attention: The following article was published over 13 years ago, and the information provided may be aged or outdated. Please keep that in mind as you read the post.

Overview

This is the second post in a series written on Dependency Injection for Android Development. In this blog, I will discuss how to take advantage of RoboGuice to inject views and other Android services into the project. If you would like a review of Dependency Injection (DI) or the basics of using DI in Android, please review part one.

In the first blog post by Adi Rosenblum, we discussed how to inject a service into the Android activity. This was a basic injection practice for use in a Java project. However, using RoboGuice we can also inject Android views, resources, and system services. Let’s begin with injecting a view.

Views

As standard Android developer practice, we commonly use the findById method to retrieve data. Adding all these initialization calls to the onCreate method unnecessary clutters and adds more complexity to the method’s real purpose.

public class AndroidWithGuiceActivity extends RoboActivity {

	@Inject
	private LoginService loginService;

	private EditText username;
	private EditText password;
	private Drawable icon;
	private String applName;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		icon = getResources().getDrawable(R.drawable.ic_launcher);
		applName = getString(R.string.app_name);

		username = (EditText) findViewById(R.id.username);
		password = (EditText) findViewById(R.id.password);

		boolean loggedIn = loginService.login(username.getText().toString(),
                                password.getText().toString());
		if (loggedIn) {
			// congrats!
		} else {
			// what did you do?!
		}
	}
}

A much cleaner way of doing the initialization is to inject the Android view objects. Using RoboGuice for injection, look how we can simplify and cleanup the previous example:

public class AndroidWithGuiceActivity extends RoboActivity {

	@Inject
	private LoginService loginService;

	@InjectView(R.id.username)
	private EditText username;

	@InjectView(R.id.password)
	private EditText password;

	@InjectResource(R.drawable.ic_launcher)
	private Drawable icon;

	@InjectResource(R.string.app_name)
	private String applName;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		boolean loggedIn = loginService.login(username.getText().toString(),
					               password.getText().toString());
		if (loggedIn) {
			// congrats!
		} else {
			// what did you do?!
		}
	}
}

The onCreate method now only has only true business logic of logging in a user. Using the InjectView annotation on the field declaration, we now don’t need to use the findById method and cast it to its appropriate view. In this simple example, you may not see the true benefit of using inject ion, but as the application becomes more complex the code will be cleaner and more maintainable.

Related Posts:  The Evolution of Python: Powering AI and Enterprise Solutions

Injecting Services

Besides injecting views, RoboGuice can inject all most any Android service object. List of some services that can injected are as Shared Preferences, Location Manager, Layout Inflater, Connectivity Manager, Wifi Manager, and more. To see the full list visit RoboGuice’s wiki page.

Bindings

For RoboGuice to know how to create an instance of object, a binding must be declared. The bindings are declared in a RoboGuice module. But if you are only using RoboGuice to inject standard views and Android services, you don’t need to create any additional bindings. All the default bindings are already defined in the library. To create a custom binding, you need to create a custom module that extends from the AbstractModule class. The bind method creates the glue that will tie an interface to its implementation.

For example: in our test application, instead of a single implementation of the UserDao object, we could have a multiple implementations that implement the IUserDao interface.

public interface IUserDao {
	public User findByUsername(String username);
}

Our UserDao implementation would now implement the new interface.

public class UserDao implements IUserDao {
	public User findByUsername(String username) {
		User result = null;
		// perform business logic/lookup of the user here

		return result;
	}
}

Here is how we define the glue that implements the correct version:

public class MyModule extends AbstractModule {
	@Override
	protected void configure() {
		// TODO Auto-generated method stub
		bind(IUserDao.class).to(UserDao.class);
	}
}

The previous example is very simple binding. Some of the more advanced features of binding are defining multiple bindings for the same type and defining the binding scope.  If you would like to learn more about bindings, visit the Google Guice wiki on binding.

Related Posts:  Boost Your Automated Testing with Cucumber and Selenium

Additional Features

Some of the additional features that RoboGuice provides that are unrelated to injection are logging and async tasks.

The RoboGuice logger provides the following enhancements over the standard logger.

  • The release builds automatically have the debug and verbose levels disabled.
  • Useful information such as application name, file, line of log message, and timestamp are automatically logged.
  • Log messages can be built using varargs arguments.
Ln.d"Hello %s, this %s application is logging using varargs.", username, applName);

— Mark Fricke, [email protected]

0 0 votes
Article Rating
Subscribe
Notify of
guest
3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments