2015-04-03 15 views
12

Utilizzando Dagger 2, sto provando a iniettare un oggetto singleton in più posizioni in un singolo ambito. Tuttavia, sembra che la mia soluzione crei invece una nuova istanza ogni volta.Daga 2 singleton non funzionanti

In questo progetto di prova, ho un MainActivity che inizializza il DaggerModule. DaggerModule fornisce gli oggetti Box e Cat, con Box che accetta Cat come parametro. Prendo anche Cat nella mia MainActivity. Infine, controllo i riferimenti di entrambe le variabili Cat iniettate (rispettivamente nel Box e nel MainActivity), ma non sono la stessa istanza.

Se si chiama providCat() due volte nel mio MainActivity, viene fornita la stessa istanza.

MainActivity:

public class MainActivity extends ActionBarActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     DaggerModule daggerModule = new DaggerModule(); 
     DaggerComponent daggerComponent = Dagger_DaggerComponent.builder() 
       .daggerModule(daggerModule).build(); 

     // Same Cat instance returned. 
     Cat cat1 = daggerComponent.provideCat(); 
     Cat cat2 = daggerComponent.provideCat(); 
     Log.d("=== cat1: ", cat1.toString()); 
     Log.d("=== cat2: ", cat2.toString()); 

     // Different Cat instance returned. Why? 
     Box box = daggerComponent.provideBox(); 
     Log.d("=== box cat: ", box.getCat().toString()); 
    } 
} 

@Module 
public class DaggerModule { 

    @Provides 
    @Singleton 
    public Cat provideCat() { 
     return new Cat(); 
    } 

    @Provides 
    @Singleton 
    public Box provideBox() { 
     return new Box(provideCat()); 
    } 

} 

@Singleton 
@Component(modules = { DaggerModule.class }) 
public interface DaggerComponent { 

    Cat provideCat(); 

    Box provideBox(); 

} 

public class Cat { 

    @Inject 
    public Cat() { 
    } 

} 

public class Box { 

    private Cat mCat; 

    @Inject 
    public Box(Cat cat) { 
     mCat = cat; 
    } 

    public Cat getCat() { 
     return mCat; 
    } 

} 

Grazie in anticipo!

Edit: Funziona se provideBox prende in un argomento del gatto e lo utilizza per creare la sicurezza, invece di chiamare provideCat direttamente da provideBox.

// Doesn't work, new Cat instance created. 
    @Provides 
    @Singleton 
    public Box provideBox() { 
     return new Box(provideCat()); 
    } 

vs

// Works, same singleton injected. 
    @Provides 
    @Singleton 
    public Box provideBox(Cat cat) { 
     return new Box(cat); 
    } 

Qual è la differenza tra chiamare provideCat nel MainActivity e farlo dall'interno provideBox nel DaggerModule? Potrebbe essere che il compilatore Dagger non elabora DaggerModule nello stesso modo in cui lo fa con le classi esterne e le annotazioni non vengono applicate se chiamo providCat?

risposta

6

Il motivo per cui volevo chiamare provideCat all'interno di provideBox era un equivoco sulla mia parte dell'interfaccia Component. Ho frainteso che l'interfaccia Component non fosse effettivamente implementata dal Modulo, quindi gli argomenti dei metodi del Modulo non dovevano essere dichiarati nei corrispondenti metodi del Componente. Se fosse stato così, mi avrebbe costretto a creare l'istanza Cat nella chiamata al metodo provideBox di MainActivity, che volevo evitare (quindi chiamata provideCat direttamente nel metodo provideBox del Modulo). In effetti, dichiarare argomenti nei metodi Component ha persino reso impossibile compilare il compilatore di Dagger.

Ma poiché i metodi Component non accettano argomenti, la soluzione era semplicemente iniettare istanze come argomenti nei metodi Module dove necessario (piuttosto che chiamare i metodi di fornitura corrispondenti all'interno del Modulo stesso), e solo dover chiamare metodi senza parametri del componente dai MainActivity come segue:

MainActivity:

Cat cat = daggerComponent.provideCat(); 
Box box = daggerComponent.provideBox(); 

Componente:

Cat provideCat(); 
Box provideBox(); <- no arguments 

Modulo:

@Module 
public class DaggerModule { 

    @Provides 
    @Singleton 
    public Cat provideCat() { 
     return new Cat(); 
    } 

    @Provides 
    @Singleton 
    public Box provideBox(Cat cat) { <- arguments 
     return new Box(cat); 
    } 

} 

The Cat istanze singleton del MainActivity e Box sono ormai la stessa cosa e non ho avuto a dichiarare loro dal MainActivity, ma Pugnale gestito tutto. Successo! Ancora non sono sicuro del motivo per cui i metodi di configurazione funzionano in modo diverso quando vengono richiamati da classi esterne piuttosto che dal modulo stesso.

+2

Il motivo per cui il comportamento è diverso è che la gestione dell'istanza viene gestita dall'implementazione del componente, non dal modulo. Quando invochi direttamente il metodo, lo chiamerai come qualsiasi altro metodo Java, ma quando lascerai che il componente unisca le dipendenze userà un 'dagger.internal.ScopedProvider' per assicurarti che ci sia una sola istanza. – gk5885

+5

Inoltre, per i tipi 'Inject'ed, puoi semplicemente annotare la classe (in questo caso' Cat' e 'Box') con' @ Singleton' direttamente ed evitare del tutto i metodi '@ Provides'. – gk5885

+0

Grazie per le informazioni e la mancia! – Johe