Android Dagger 2 POJO field Inject null

2019-04-28 03:47发布

问题:

Just started using Dagger 2 today and I'm a bit confused on how exactly I need to set everything up.

I'm trying to inject a POJO, but it's always null. First, some code:

App.java

private AppComponent appComponent;

@Override
public void onCreate() {
    super.onCreate();
    appComponent = DaggerAppComponent
            .builder()
            .appModule(new AppModule(this))
            .build();
}

public AppComponent component() {
    return appComponent;
}

AppModule.java

@Module
public class AppModule {
    private Application app;

    public AppModule(Application app) {
        this.app = app;
    }

    @Provides @Singleton
    public Application application() {
        return app;
    }
}

AppComponent.java

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(App application);
    Application application();
}

NetworkingManager.java

@Singleton
public class NetworkingManager {
    private Context ctx;

    @Inject
    public NetworkingManager(Context context) {
        this.ctx = context;
    }
}

NetModule.java

@Module
public class NetModule {
    @Provides @Singleton
    public NetworkingManager provideNetworkingManager(Application application) {
        return new NetworkingManager(application);
    }
}

NetComponent.java

@Singleton
@Component(modules = {NetModule.class},
        dependencies = {AppModule.class})
public interface NetComponent {
    void inject(NetworkingManager networkingManager);
}

SomeClass.java

@Inject
NetworkingManager networkingManager;

public void doSomethingWithNetworkManager() {
    networkManager.doStuff();
}

I've spent a good deal of time looking through lots of tutorials, SO questions, and examples, but I haven't been able to figure out what I'm doing wrong.

I'm 99% certain I have something setup wrong, but I haven't been able to figure out what.

回答1:

Based on your comment, you want to make NetworkingManager available everywhere in your application.

Let's start with your definition of the Component:

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(App application);
}

This tells Dagger that this component will be injecting the App class. Now here you can also tell Dagger other classes you would like to inject. So if you want to also inject an Activity for example you would add:

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(App application);
    void inject(MainActivity activity) //Where MainActivity is a class that extends Activity.
}

Please note that this is not the best way, IMO, to share Application wide dependencies; you should create a Component that inherits from AppComponent and make AppComponent expose the desired shared dependencies.

Now let's look at your module class:

@Module
public class NetModule {
    @Provides @Singleton
    public NetworkingManager provideNetworkingManager(Application application) {
        return new NetworkingManager(application);
    }
}

Here you are @Provideing a NetworkingManager, that is fine. Your NetworkingManager requires an Application (a Context really), why not provide App inside of NetworkingManager?, or even better why not provide NetworkingManager inside the AppModule since AppModule should @Provide things that are common for the whole Application:

@Module
public class AppModule {
    private Application app;

    public AppModule(Application app) {
        this.app = app;
    }

    @Provides @Singleton
    public Application application() {
        return app;
    }

    @Provides @Singleton
    public NetworkingManager provideNetworkingManager(Application application) {
        return new NetworkingManager(application);
    }
}

Now inside your App class:

public class App extends Application {
    private AppComponent appComponent;

@Override
public void onCreate() {
    super.onCreate();
    appComponent = DaggerAppComponent
            .builder()
            .appModule(new AppModule(this))
            .build();
   appComponent.inject(this);
}

public AppComponent component() {
    return appComponent;
 }
}

And in our hypothetical MainActivity:

public class MainActivity extends Activity {

private AppComponent appComponent;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    appComponent = ((App)getApplicationContext()).getAppComponent();
    appComponent.inject(this);
   }
 }

It seems that you are not using @Component(dependencies = {...}) correctly. dependencies is used when you want to expose a dependency from one Component to another using the mechanism I mentioned above.