Reputation: 16728
I have learned a lot developing my current android app, enough to see that I made some mistakes. For example I now know that all the new Blah(...)
statements below are bad from a test point of view. Are there established techniques to safely migrate existing code like this to use a form of dependency injection? By "safe" I mean low likely hood to break by app. I was thinking of just adding setter methods for each dependency so that I could pass in mock objects during test, but that seems a bit hackish.
@Override
public void onCreate() {
super.onCreate();
System.out.println("creating the LocationMonitorService");
mBus = BusProvider.getInstance();
mBus.register(this);
markerRequestTimer = new GetMarkerRequestTimer(10*60000,10000);
pushRequestTimer = new PushRequestTimer(10*60000,60000);
deviceLocationClient = new DeviceLocationClient(this);
gcmKeepAliveIntent = new Intent("com.gmail.npnster.first_project.gcmKeepAlive");
gcmKeepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, gcmKeepAliveIntent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, 4*60*1000, gcmKeepAlivePendingIntent);
}
class GetMarkerRequestTimer extends CountDownTimer {
public GetMarkerRequestTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
// TODO Auto-generated constructor stub
}
@Override
public void onTick(long millisUntilFinished) {
System.out.println("requesting new markers from server");
mBus.post(new GetMapMarkersRequest());
}
@Override
public void onFinish() {
System.out.println("time out reached ending request for markers from the server");
}
}
Upvotes: 2
Views: 161
Reputation: 4751
Seeing you are on android, I am assuming you use Dagger. If using Guice, replace ObjectGraph with Injector. The rest is the same.
I haven't had to do this refactoring on android before but have done it in server-side java projects. You can incrementally add dependency injection. Starting with:
class A {
B b = new B();
}
class B {
C c = new C();
}
class C {
}
Now let's assume we want to refactor B to use DI, but without changing the structure of A.
Create a new ObjectGraph somewhere central. Make it static and public (bad in general, good for incremental transition)
public void onCreate() {
ObjectGraph objectGraph = ObjectGraph.create(new MyModule());
Global.objectGraph = objectGraph; //Where global is just a class with a public static field called objectGraph
MyApp app = objectGraph.get(App.class);
...
}
So now you can refactor B:
class B {
private final C c;
@Inject
B(C c) {
this.c = c;
}
}
B is now injected and testable. To get rid of the new call in A, replace
new B()
with
Global.objectGraph.get(B.class)
Which effectively gives you a fully refactored B and a backwards-compatible A. When, if ever you get rid of all the static references to the global object graph, you can delete it.
Upvotes: 2