简体   繁体   中英

Dagger2 injection not happening - injected field is turning out to be null

I am struggling with my first Dagger2 project.

I want to inject a Context into a singleton class. Here is a minimal example (I have removed package names, imports and have not included layouts, values or manifest files). This code ideally should pick up the string <string name="app_name">My Application</string> .

MainApplication.java:

public class MainApplication extends Application {

    private MainComponent mComponent;

    @Override
    public void onCreate() {

        super.onCreate();

        mComponent = DaggerMainComponent.builder()
                .mainModule(new MainModule(this))
                .build();

        getComponent().inject(this);
    }

    public MainComponent getComponent() {

        return mComponent;
    }
}

MainModule.java:

@Module
public class MainModule {

    private final MainApplication mApplication;

    public MainModule(MainApplication application) {

        this.mApplication = application;
    }

    @Provides
    @Singleton
    public Context getApplicationContext() {

        return mApplication.getApplicationContext();
    }
}

MainComponent.java:

@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {

    void inject(MainApplication application);
}

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tvAppName = findViewById(R.id.main_app_name);
        tvAppName.setText(MainHelper.getInstance().getApplicationName());
    }
}

MainHelper.java:

public class MainHelper {

    private static final MainHelper INSTANCE = new MainHelper();

    @Inject
    Context mContext;

    public static MainHelper getInstance() {

        return INSTANCE;
    }

    public String getApplicationName() {

        return mContext.getString(R.string.app_name);
    }
}

What actually happens is that I get this exception upon app launch itself:

2019-11-14 18:46:47.561 9116-9116/com.example.myapplication E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.myapplication, PID: 9116
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapplication/com.example.myapplication.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getString(int)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2830)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2909)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1606)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6592)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getString(int)' on a null object reference
        at com.example.myapplication.MainHelper.getApplicationName(MainHelper.java:21)
        at com.example.myapplication.MainActivity.onCreate(MainActivity.java:16)
        at android.app.Activity.performCreate(Activity.java:6984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1235)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2783)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2909) 
        at android.app.ActivityThread.-wrap11(Unknown Source:0) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1606) 
        at android.os.Handler.dispatchMessage(Handler.java:105) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6592) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769) 

Basically, the mContext object in MainHelper is null which to me means that the injection didn't work at all. What is going wrong? This code seems to adhere to pretty much all the tutorials out there.

You're not injecting the Context to your MainHelper . I suggest you refactor your MainHelper class to obtain the Context via Constructor injection (you should do this for all classes you own):

@Singleton
public class MainHelper {

   private final Context context;

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

}

The @Inject annotation on the constructor should be enough so that Dagger knows to instantiate/create MainHelper for you. And then in order for this MainHelper class to be injected to your MainActivity , you first need to tell Dagger that you need to inject dependencies to your MainActivity . You already did something similar for your MainApplication class:

@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainApplication application);
    void inject(MainActivity activity);
}

Then on your MainActivity , you inject MainHelper by calling the inject method that Dagger generates for you:

public class MainActivity extends AppCompatActivity {

     @Inject
     MainHelper helper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ((CustomApplication) getApplication()).getComponent().inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tvAppName = findViewById(R.id.main_app_name);
        tvAppName.setText(helper.getApplicationName());
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM