2015-02-04 5 views
2

Я новичок в кинжале и вначале сталкиваюсь с некоторыми проблемами. До сих пор у меня есть простая структура в моем проекте. Мой инъекции модуль:Кинжал - вложенные инъекции, нужно ли вызывать инъекцию()?

@Module(
    injects = {GameBoardFragment.class, GameManager.class}, 
    complete = false, 
    library = true 
) 

public class GameObjectsProviderModule { 
private final Application mApplication; 

public GameObjectsProviderModule(Application application){ 
    this.mApplication = application; 
} 

@Provides 
@Singleton 
public GameManager provideGameManager(){ 
    return new GameManager(); 
} 

@Provides 
public Board getBoard(){ 
    return new Board(); 
} 

@Provides @Singleton @ForApplication Context provideAppContext() { 
    return mApplication; 
} 

Мой упрощенный пользовательский класс приложение выглядит следующим образом:

public class MyApp extends Application { 
private static ObjectGraph mApplicationGraph; 

@Override public void onCreate() { 
    super.onCreate(); 

    mApplicationGraph = ObjectGraph.create(new GameObjectsProviderModule(this)); 
} 

public static ObjectGraph getObjectGraph(){ 
    return mApplicationGraph; 
} 
} 

А теперь, мой фрагмент выглядит так:

public class GameBoardFragment extends Fragment { 

@Inject 
GameManager mGameManager; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
    MyApp.getObjectGraph().inject(this); 

    View root = inflater.inflate(R.layout.fragment_game_board, container, false); 
    findViews(root); 
    confViews(); 

    return root; 
} 
} 

И, наконец, мой GameManager класс

public class GameManager { 

    @Inject Board mBoard; 

    public GameManager(){ 
     MyApp.getObjectGraph().inject(this); 
    } 
} 

Andy эй, это работает! Отлично. Но мой вопрос, почему он не работает в случае, если я закомментировать эту строку:

MyApp.getObjectGraph().inject(this); 

ли мы всегда явно вызывать впрыснуть функцию(), чтобы сделать все необходимые инъекции иметь место события вложенных объектов? Это выглядит не так, как показывает пример кофе производитель:

https://github.com/square/dagger/tree/master/examples/simple/src/main/java/coffee

Почему я должен назвать инъекционные() в классе GameManager, чтобы заставить его работать?


Edit:

consturctor инъекции подход работает просто отлично.

Но для будущего использования я попытался запустить полевую инъекцию, и до сих пор мне не удалось.

Я закомментирована как @Provide методов из модуля и я сделал GameManager выглядеть следующим образом:

@Singleton 
public class GameManager { 

@Inject Board mBoard; 

@Inject 
    public GameManager(){ 
} 
} 

и платы:

public class Board { 

    @Inject 
    public Board() { 
    } 
} 

Однако материнка не получает инстанцированную. Я попробую больше, и я полагаю, что я выясню правильное решение.

ответ

2

Вы должны использовать инъекцию конструктора (например, Thermosiphon) и избегать инъекции впрыска, если это необходимо. Например, пусть ваш GameManager имеет Board в качестве аргумента конструктора:

@Singleton 
public class GameManager { 

    private final Board mBoard; 

    @Inject 
    public GameManager(final Board board){ 
     mBoard = board; 
    } 
} 

Dagger будет использовать этот конструктор для создания экземпляра GameManager (отсюда @Inject аннотаций), и обратите внимание, что требуется Board экземпляра. Используя ObjectGraph, он сначала создаст Board, и этот экземпляр создаст GameManager. Вы можете удалить метод @Provides GameManager, если вы это сделаете.

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

public class Board { 

    @Inject 
    public Board() { 
    } 
} 

Если вы не хотите использовать инъекции конструктора, проблема заключается в том, что вы сказали Dagger что вы хотите создать свой экземпляр GameManager самостоятельно (потому что у вас есть метод @Provides GameManager). Если вы удалите этот метод и дайте Dagger его создать для вас, как указано выше, но без параметра Board в конструкторе, Dagger также заметит поле @Inject Board и добавит его также.


Последнее замечание. Удалите заявления library = true и complete = false! В этом примере это не обязательно. Добавляйте их только в том случае, если вы действительно знаете, что делаете. Не имея их, Кинжал создаст ошибки времени компиляции, чтобы уведомить вас, что что-то не так. Если вы включите их, вы сообщите Кинжалу: «Эй, я знаю, что делаю, не волнуйтесь, все правильно», на самом деле это не так.


Редактировать

Цитата с сайта Dagger1:

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

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

@Singleton 
public class GameManager { 

    @Inject Board mBoard; 

    public GameManager(){ // Or remove the constructor entirely since it's empty 
    } 
} 

Поскольку существует @Inject аннотации на Board поля, Кинжал будет знать, чтобы использовать конструктор без аргументов.

+0

Спасибо за приятное объяснение! Вы очистили мои сомнения. – JohnC

1

Я боролся с той же проблемой, что и большинство примеров кинжалов повсюду, используя модуль с помощью Provides, и мне было трудно найти полный пример, который просто не использует Provides.

Я создал этот. Он использует инъекцию поля (не встраивание конструктора) и отлично работает через иерархию, не требуя вызова для инъекций. Я использую Dagger 1.2.2.

Main.java

import javax.inject.*; 
import dagger.*; 
import dagger.ObjectGraph; 

public class Main { 

    public static void main(String[] args) { 

     ObjectGraph objectGraph = ObjectGraph.create(new CarModule()); 
     Car car = objectGraph.get(Car.class); 
     car.start(); 
    } 
} 

CarModule.Java

import dagger.Module; 

@Module(injects = Car.class) 
public class CarModule { 

} 

Car.Java

import javax.inject.*; 

public class Car { 
    @Inject public Engine engine; 

    @Inject Car() { 
     System.out.println("Car constructor"); 
    } 
    public void start() { 
     engine.start(); 
    } 

} 

Engine.Java

import javax.inject.*; 
public class Engine { 
    @Inject WaterPump waterPump; 

    Engine() { 
     System.out.println("Engine Constructor"); 
    } 
    void start() { 
     waterPump.run(); 
     System.out.println("starting engine."); 
    } 
} 

WaterPump.Java

import javax.inject.*; 
public class WaterPump { 
    @Inject WaterPump() { 
     System.out.println("WaterPump Constructor."); 
    } 

    public void run() { 
     System.out.println("WaterPump running."); 
    } 
} 

Выход:

Car constructor 
Engine Constructor 
WaterPump Constructor. 
WaterPump running. 
starting engine. 

без CarModule, объявляющего его впрыскивает Car.Class это не работает. Вы получаете:

Исключение в потоке «основного» java.lang.IllegalArgumentException: Нет инъекционные зарегистрирован для членов/автомобиля. Вы должны явно добавить его в опцию «впрыски» в одном из ваших модулей.

Но обратите внимание, что CarModule не @Provides ничего. Это кинжал, который автоматически создает все зависимости, используя граф объектов.

Также обратите внимание, что вам не нужно размещать аннотацию @Inject по умолчанию, если у вас есть поле @Inject в классе. Для класса Car я использовал его как для конструктора, так и для поля и в классе Engine. Я использовал его только для поля, а не для конструктора, и он отлично работает, как описано.

+0

в вашем ответе неправильно, вы дважды объявляли класс «Двигатель» * Как декларация класса 'WaterPump' так же, как класс' '' '' двигателя'' –

+0

Спасибо. Я починил это. – Ronen

+0

У меня есть аналогичная нерешенная проблема http://stackoverflow.com/questions/44093671/dagger-field-injection-not-working-with-simple-java-classes, но я использую кинжал2. Я не знаю, чего не хватает. Любой вход высоко оценен. –

Смежные вопросы