Sunday, April 3, 2011

Dependency Injection Android (Rapid Prototyping)

In order to achieve the nirvana of real-time iterations for Android (making changes to android applications at runtime without recompilation / redeploy).  I'm designing a client-server model to provide state/properties and "publish" changes to the client (Android device).  The key to all of this is using dependency injection.  If all objects are configured and wired together from the outside (as dependency injection dictates), then, in "real-time editing mode" the changes can be applied to the program state.

In "production mode" there will be no client-server architecture, all of the configuration will be done locally (also through dependency injection).  In development/debug/real-time-editing mode the configuration will be either
1) configured locally, then uploaded to the server, and the server will be polled for changes (publish&poll)
2) configured remotely (will "pull" the configuration/properties from the remote server) (pull&poll)

So off the bat we have a few issues to contend with.  First we don't want all the client server code to be integrated and deployed with the production application.  I will use the strategy described in an earlier post of development/release aware builds for accomplishing this (Basically I have multiple application deployment "topologies", each consisting of potentially (many) eclipse projects ..

the "debug" deployment topology version of the release which contains
1) the base project
2) any "library" projects needed to run the application
2) a debug android library project  containing overrides and configuration as well as any library code and dependencies for the client-server architecture (this is an android "library project")

the "production/release" version of the project which contains
1) the base project
2) any "library" projects needed to run the application

The main "inflection point" or way I provide this indirection is (at Runtime) during initialization, I check for the existence of a specific class (which is only available in the Debug project lets call it DebugMode.class)... if this class exists,  it is created, and in it's constructor it will perform all of the additional configuration and initialization as well as any property overrides to make the application run in "Client-Server mode".

So building and deploying the application in release mode requires nothing special, building and deploying the application in debug mode requires you to change the classpath to add the debug project. (That way none of the debug specific code is deployed to the release app unnecessarily)... this can be done either in eclipse directly or in Maven/Ant. (with different release targets)

Another issue I am working on is selecting a DI framework which works for Android, at the moment I am using robo-guice... which I'm starting to like.  Having those @Inject tags makes things relatively easy to read.

package example.roboguice;

import roboguice.activity.RoboActivity;
import android.os.Bundle;
import android.util.Log;

import com.google.inject.Inject;

public class MyRoboGuiceActivity extends RoboActivity {
    @Inject protected MyInterface someInterface;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
   
    public void onStart() {
     super.onStart();
     Log.e("Guice", someInterface.getName());
    }
}
...Also I like that "Modules" (which "wire" everything together) are relatively straightforward

package example.roboguice;

import android.util.Log;
import roboguice.config.AbstractAndroidModule;

public class MyRoboGuiceModule extends AbstractAndroidModule {
 protected void configure() {
  Log.e("MyModule", "Loading Module ... SomeInterface");
  bind(MyInterface.class).to(MyImpl.class);
 }
}


We'll see how things turn out

No comments:

Post a Comment