【问题标题】:Dagger 2 - unable to inject objectDagger 2 - 无法注入对象
【发布时间】:2015-06-08 18:27:40
【问题描述】:

我正在尝试在 Android 应用程序中进行非常简单的依赖注入。我使用 dagger 2 作为 DI 工具。

问题是没有发生注入:

这是我的代码:

//对 Motor.java 充满敬畏。

public class Motor {

    private int rpm;

    public Motor(){
        this.rpm = 10; //default will be 10
    }

    public int getRpm(){
        return rpm;
    }

    public void accelerate(int value){
        rpm = rpm + value;
    }

    public void brake(){
        rpm = 0;
    }
}

这里是使用电机类的 Vehicle.java:

import javax.inject.Inject;


public class Vehicle {

    private Motor motor;

    @Inject
    public Vehicle(Motor motor){
        this.motor = motor;
    }

    public void increaseSpeed(int value){
        motor.accelerate(value);
    }

    public void stop(){
        motor.brake();
    }

    public int getSpeed(){
        return motor.getRpm();
    }
}

然后我创建了一个 VehicleModule.java 类来定义我的提供者:

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;



@Module
public class VehicleModule {

    @Provides
    @Singleton
    Motor provideMotor(){
        return new Motor();
    }

    @Provides @Singleton
    Vehicle provideVehicle(){
        return new Vehicle(new Motor());
    }
}

然后我有一个带注释的接口组件,定义如下:

import javax.inject.Singleton;

import Modules.VehicleModule;
import dagger.Component;

@Singleton
@Component(modules = {VehicleModule.class})
public interface VehicleComponent {

    Vehicle provideVehicle();

}

这是我应该注入的 Android mainactivity 类,但它没有,任何人都可以帮忙:

import javax.inject.Inject;

public class MainActivity extends ActionBarActivity {

    @Inject
    Vehicle vehicle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();
    }
}

我在车辆上得到一个空指针异常:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.uen229.myapplication.Vehicle.getSpeed()' on a null object reference

顺便说一下,我的 gradle 依赖项如下所示:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
    compile 'com.google.dagger:dagger:2.0'
}

【问题讨论】:

    标签: android dependency-injection dagger-2


    【解决方案1】:

    这是我的 Android mainactivity 类,应该注入但它不是

    当您使用@Inject 注释某些内容时,您会期待神奇的事情发生。虽然神奇的事情发生,但它并不是那么神奇。您需要通过实例化 Dagger 生成的组件实现自己来完成。

    您可以通过多种方式做到这一点,我将描述两种。


    首先,在您的MainActivityonCreate

    private Vehicle vehicle; // Note, no @Inject annotation
    
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
    
      VehicleComponent vehicleComponent = DaggerVehicleComponent.create();
      this.vehicle = vehicleComponent.provideVehicle();
    
      Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();
    }
    

    在这种情况下,您创建一个由 Dagger 实现的VehicleComponent 实例,并从中获取Vehicle 实例。 vehicle 字段未由 @Inject 注释。这样做的好处是字段可以是private,这是一件好事。


    其次,如果您确实希望 Dagger 注入您的字段,您需要在您的 VehicleComponent 中添加一个 inject 方法:

    @Singleton
    @Component(modules = {VehicleModule.class})
    public interface VehicleComponent {
    
      Vehicle provideVehicle();
    
      void inject(MainActivity mainActivity);
    }
    

    在您的MainActivity 类中,您调用inject(this),这将填充vehicle 字段:

    @Inject
    Vehicle vehicle; // Note, package-local
    
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
    
      VehicleComponent vehicleComponent = DaggerVehicleComponent.create();
      vehicleComponent.inject(this);
    
      Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();
    }
    

    这带来了一些额外的配置,但有时是必要的。 不过我喜欢第一种方法。


    作为最后的评论,让我们看看你的VehicleModule真的使用 Dagger 的力量。

    您可以为自己制作 Dagger,而不是使用模块自己创建实例。你已经用@Inject 注释了Vehicle 构造函数,所以Dagger 会知道使用这个构造函数。然而,它需要一个Motor 的实例,它并不知道。如果你也给Motor的构造函数加上@Inject注解,并且用@Singleton注解Motor类,就可以完全去掉VehicleModule

    例如:

    @Singleton
    public class Motor {
    
        private int rpm;
    
        @Inject // Just an annotation to let Dagger know how to retrieve an instance of Motor.
        public Motor(){
            this.rpm = 10; //default will be 10
        }
    
        public int getRpm(){
            return rpm;
        }
    
        public void accelerate(int value){
            rpm = rpm + value;
        }
    
        public void brake(){
            rpm = 0;
        }
    }
    

    您的Vehicle 班级:

    @Singleton
    public class Vehicle {
    
        private Motor motor;
    
        @Inject
        public Vehicle(Motor motor){
            this.motor = motor;
        }
    
        public void increaseSpeed(int value){
            motor.accelerate(value);
        }
    
        public void stop(){
            motor.brake();
        }
    
        public int getSpeed(){
            return motor.getRpm();
        }
    }
    

    您现在可以安全地删除 VehicleModule 类,并删除您的 VehicleComponent 中对它的引用。

    【讨论】:

    • 它说在 IDE 中找不到 DaggerVehicleComponent。有任何想法吗 ?我删除了 Inject 注释并遵循您的第一个方法,因此我可以创建私有方法。它的包本地。现在一切都在本地打包。但它没有找到 DaggerVehicleComponent。我猜这是自动生成的。
    • 查看我的回答 here,了解如何让 Android Studio 找到生成的类。
    • 使用此应用插件:'com.neenbedankt.android-apt' 并在 build.gradle 文件中:classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' 使其自动为我生成课程。你的解释非常好。谢谢先生。
    【解决方案2】:

    您缺少以下步骤

    您已经在应用程序类中创建了这样的模块

    public class D2EApplication extends Applicaiton {
        public static D2EComponent component(Context context) {
                return ((D2EBaseApplication) context.getApplicationContext()).component;
            }
    
            public final static class DaggerComponentInitializer {
    
                public static D2EComponent init(D2EBaseApplication app) {
                    return DaggerD2EComponent.builder()
                            .systemServicesModule(new VehicleModule(app))
                            .build();
                }
    
            }
        }
    

    并将其注入到活动中

    D2EApplication.component(this).inject(this);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-27
      • 2022-09-30
      • 2020-02-29
      • 2018-06-13
      相关资源
      最近更新 更多