Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dagger for Android: Injecting an Activity to the object graph after calling setContentView

I want to use Dagger on Android to inject an instance of an Activity into another class as follows:

class PresentationLayer{
    Activity mActivity;
    
    @Inject
    public PresentationLayer(Activity activity){
        this.mActivity = activity;
    }
    
    public void presentData(User user){
        ((TextView)mActivity.findViewById(R.id.username))
            .setText(user.getName());
        //...
        //...
    }
}

I am able to do the injection, but all fields of the Activity are null at the time of injection.

Here's how I am doing the injection:

My Activity is a module in itself.

@Module(
    complete = false
)
class MainActivity extends Activity{
    
    @Override
    public void onCreate(Bundle bundle){
        super.onCreate(bundle);
        setContentView(R.layout.main_activity);
        ObjectGraph objectGraph = CustomApplication.getObjectGraph();
        PresentationLayer pres = objectGraph.get(PresentationLayer.class);
    }
    
    @Provides Activity provideActivity(){
        return this;
    }
    
    
}

This is my main module

@Module(
    entryPoints = PresentationLayer.class,
    includes = MainActivity.class
)
class DaggerModule{
    @Provides PresentationLayer providePresentation(Activity activity){
        return new PresentationLayer(activity);
    }
}

And my Application class that bootstraps the object graph.

class CustomApplication extends Application{

    private static ObjectGraph sObjectGraph;
    @Override
    public void onCreate(){
        sObjectGraph = ObjectGraph.create(new DaggerModule());
    }
    
    static getObjectGraph(){
        return sObjectGraph;
    }
}

I am looking for a way to explicitly perform the injection after I call setContentView.

How do I go about doing this?


EDIT 1:

I got it to work like this - however I am not sure if this is the "right way". What I do is

  1. Pass in the Activity to the Module constructor
  2. Ensure that I build the ObjectGraph after I do setContentView() so that a proper Activity instance is passed in to the ObjectGraph.

My Activity is no longer a dagger Module.

This translates to the following in code:

@Module(
    entryPoints = PresentationLayer.class
)
class DaggerModule{

    private Activity mActivity;
    
    public DaggerModule (Activity activity){
        this.mActivity = activity;
    }
    
    @Provides PresentationLayer providePresentation(){
        return new PresentationLayer(mActivity);
    }
}

And this is how my Activity looks:

class MainActivity extends Activity{
    
    @Override
    public void onCreate(Bundle bundle){
        super.onCreate(bundle);
        setContentView(R.layout.main_activity);
        ObjectGraph objectGraph = CustomApplication.getObjectGraph(this);
        PresentationLayer pres = objectGraph.get(PresentationLayer.class);
        User user = //get the user here
        pres.presentData(user);
    }
}

This solution seems to address the points raised by Jesse Wilson in this answer. However, I am concerned about the performance, since the ObjectGraph is going to be built every time the Activity is created.

Any thoughts?

like image 450
curioustechizen Avatar asked Dec 21 '12 07:12

curioustechizen


People also ask

How do you inject an activity?

To inject an object in the activity, you'd use the appComponent defined in your Application class and call the inject() method, passing in an instance of the activity that requests injection.

How does Dagger injection work?

Dagger automatically generates code that mimics the code you would otherwise have hand-written. Because the code is generated at compile time, it's traceable and more performant than other reflection-based solutions such as Guice. Note: Use Hilt for dependency injection on Android.

What is @inject in Android?

Dependency injection provides your app with the following advantages: Reusability of classes and decoupling of dependencies: It's easier to swap out implementations of a dependency.

What is Dagger dependency injection?

Dagger is a fully static, compile-time dependency injection framework for Java, Kotlin, and Android. It is an adaptation of an earlier version created by Square and now maintained by Google.


1 Answers

Unfortunately this probably isn't going to work with Dagger, or with most other dependency injection frameworks. The problem is that the lifecycle of Activity doesn't cleanly line up with the lifecycle of PresentationLayer. For example, when you rotate your screen, Android will destroy the activity and create another one in its place. There's no hook for PresentationLayer to participate in that.

At Square we've been using Otto to communicate between activities and their backends and it has worked well. See Eric Burke's sample code project for an example.

like image 140
Jesse Wilson Avatar answered Oct 27 '22 05:10

Jesse Wilson