2015-06-08 2 views
1

Im пытается сделать очень простую инъекцию зависимостей в приложении для Android. Я использую кинжал 2 как инструмент DI.Dagger 2 - не удалось ввести объект

вопрос нет инъекции не встречающийся:

вот мой код:

// вот 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' 
} 

ответ

5

вот мой Android класс mainactivity, который должен быть введен, но его не

Вы ожидаете, что волшебные вещи произойдут, когда вы что-нибудь заметите с помощью @Inject. В то время как магические вещи будет, это не , что магический. Вам нужно будет сделать это самостоятельно, создав экземпляр реализации компонентов, созданных кинжалом.

Вы можете сделать это несколькими способами, я опишу два.


Во-первых, в ваших MainActivity «ы onCreate:

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(); 
} 

В этом случае, вы создаете экземпляр VehicleComponent, реализованный Dagger, и принести экземпляр Vehicle из него. Поле vehicle не аннотируется @Inject. Это имеет то преимущество, что поле может быть private, что очень полезно.


Во-вторых, если вы хотите Dagger вводить ваши поля, вам нужно добавить inject метод к вашему VehicleComponent:

@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.

Вместо того чтобы использовать модуль для создания экземпляров самостоятельно, вы можете сделать кинжал таким, как вы. Вы уже аннотировали конструктор Vehicle с @Inject, поэтому Кинжал будет знать, как использовать этот конструктор. Однако ему нужен экземпляр Motor, о котором он не знает. Если вы добавите аннотацию @Inject к конструктору Motor, а также аннотируйте класс Motor с помощью @Singleton, вы можете полностью избавиться от 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.

+0

его высказывание оно не может найти DaggerVehicleComponent в IDE. есть идеи ? Я удалил аннотацию Inject и следую вашему первому методу, поэтому могу делать частные методы. его пакет локальный. Теперь пакет Everythings локальный. но он не находит DaggerVehicleComponent. Я предполагаю, что это то, что автоматически генерируется. – j2emanue

+0

Ознакомьтесь с моим ответом [здесь] (http://stackoverflow.com/a/29707308/675383) о том, как заставить Android Studio найти сгенерированные классы. – nhaarman

+1

, используя этот применимый плагин: «com.neenbedankt.android-apt» и в файле build.gradle: classpath «com.neenbedankt.gradle.plugins: android-apt: 1.4» заставил его автоматически генерировать классы для меня. Ваше объяснение очень хорошее. Спасибо, сэр. – j2emanue

0

вы отсутствуете следующие шаги

вы должны создать модуль, как это приложение класса

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); 
Смежные вопросы