2016-03-09 18 views
13

SfondoDagger 2 iniettando più istanze dello stesso tipo di oggetto

sto convertendo la mia app all'architettura MVP e ho trovato Dagger 2 per essere utile per iniettare le dipendenze quando necessario. La mia app ha bisogno di comunicare con due web apis (la mia e una terza parte). Potrebbero esserci delle volte in cui le richieste alla mia API e alla API di terze parti potrebbero essere attivate contemporaneamente. Uso Retrofit per comunicare con queste apis e utilizzare GSON per la serializzazione/deserializzazione.

Quello che ho fatto prima

ho creato due RestAdapters Retrofit e usato modello Service Locator per ottenerli quando necessario. Il RestAdapter pensato per essere utilizzato per la mia API personale include GSONConverter con alcuni TypeAdapter personalizzati poiché non desidero la deserializzazione JSON 1: 1 della mia risposta nell'app. L'altro RestAdapter è destinato all'API di terze parti e utilizza un altro GSONConverter con una specifica politica di denominazione dei campi.

Problema

Sto cercando di usare al posto di DI Service Locator per ottenere la mia RestAdapter (e l'interfaccia API). Io ho la mia impostazione di classe NetModule come segue

@Module 
public class NetModule { 

    private static final String MY_API_URL = "my_api_url"; 
    private static final String THIRD_PARTY_API_URL = "third_party_api_url"; 

    @Provides 
    @Singleton 
    Cache provideOkHttpCache(Application application) { 
     int cacheSize = 10 * 1024 * 1024; // 10 MiB 
     return new Cache(application.getCacheDir(), cacheSize); 
    } 

    @Provides 
    @Singleton 
    OkHttpClient provideOkHttpClient(Cache cache) { 
     OkHttpClient client = new OkHttpClient(); 
     client.setCache(cache); 
     return client; 
    } 

    @Provides 
    @Singleton 
    TypeAdapter<MyClass> provideMyAPITypeAdapter() { 
     return new TypeAdapter<MyClass>() { 
      // implementation ignored 
     }; 
    } 

    @Provides 
    @Named("myApiGson") 
    Gson provideGsonForMyAPI(TypeAdapter<MyClass> adapter) { 
     return new GsonBuilder() 
       .registerTypeAdapter(MyClass.class, adapter) 
       .setDateFormat("yyyy-MM-dd HH:mm:ss") 
       .create(); 
    } 

    @Provides 
    @Named("thirdPartyApiGson") 
    Gson provideGsonForThirdPartyAPI() { 
     return new GsonBuilder() 
       .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) 
       .create(); 
    } 

    @Provides 
    @Named("myApiRestAdapter") 
    RestAdapter provideMyRestAdapter(Gson gson, OkHttpClient okHttpClient) { 
     return new RestAdapter.Builder() 
       .setEndpoint(MY_API_URL) 
       .setConverter(new GsonConverter(gson)) 
       .setClient(new OkClient(okHttpClient)) 
       .build(); 
    } 

    @Provides 
    @Named("thirdPartyApiRestAdapter") 
    RestAdapter provideThirdPartyRestAdapter(Gson gson, OkHttpClient okHttpClient) { 
     return new RestAdapter.Builder() 
       .setEndpoint(THIRD_PARTY_API_URL) 
       .setConverter(new GsonConverter(gson)) 
       .setClient(new OkClient(okHttpClient)) 
       .build(); 
    } 

    @Provides 
    @Singleton 
    MyAPI provideMyAPI(RestAdapter adapter){ 
     return adapter.create(MyAPI.class); 
    } 

    @Provides 
    @Singleton 
    ThirdPartyAPI provideThirdPartyAPI(RestAdapter adapter){ 
     return adapter.create(ThirdPartyAPI.class); 
    } 
} 

Come si può vedere sopra nel codice, il NetModule ha metodi per restituire due oggetti GSON e due oggetti RestAdapter. Le mie domande sono;

  1. Come posso fare in modo che le dipendenze corrette vengono iniettati durante la creazione di specifici RestAdapter & interfacce API? (provideMyRestAdapter() richiede GSON tornato da provideGsonForMyAPI() e provideMyAPI() richiede RestAdapter tornato da provideMyRestAdapter().)

  2. Come posso fare in modo che solo due casi di RestAdapter (uno per il mio api e altri per l'API di terze parti) vengono mai creato durante la vita dell'applicazione poiché la creazione di RestAdapter è considerata costosa. Sto usando l'attributo @Named sui metodi che restituiscono RestAdapters. Ad esempio, quando si inserisce direttamente una dipendenza in un campo come questo: @Inject("myApiRestAdapter") RestAdapter myRestadapter; Dagger 2 creerà ogni volta un nuovo RestAdapter o ne utilizzerà uno creato prima (come @Singleton ma per un oggetto specifico)?

Ho appena iniziato a utilizzare Dagger 2 e la mia comprensione di come utilizzarlo potrebbe essere ancora errata. Per favore correggimi se sto facendo qualcosa di sbagliato qui. Grazie per aver risposto a questa lunga domanda.

risposta

22

Sei già a metà della soluzione. Per completare la soluzione provare a effettuare le seguenti operazioni:

@Provides 
@Named("myApiRestAdapter") 
RestAdapter provideMyRestAdapter(@Named("myApiGson") Gson gson, OkHttpClient okHttpClient) { 
    return new RestAdapter.Builder() 
      .setEndpoint(MY_API_URL) 
      .setConverter(new GsonConverter(gson)) 
      .setClient(new OkClient(okHttpClient)) 
      .build(); 
} 

@Provides 
@Named("thirdPartyApiRestAdapter") 
RestAdapter provideThirdPartyRestAdapter(@Named("thirdPartyApiGson") Gson gson, OkHttpClient okHttpClient) { 
    return new RestAdapter.Builder() 
      .setEndpoint(THIRD_PARTY_API_URL) 
      .setConverter(new GsonConverter(gson)) 
      .setClient(new OkClient(okHttpClient)) 
      .build(); 
} 

Per assicurarsi che solo due casi di vostri RestAdapters vengono creati durante il ciclo di vita dell'applicazione, annotare sia i metodi che forniscono RestAdapter con @Singleton come avete fatto con il vostro altri metodi. Per quanto riguarda la tua altra domanda, se Dagger 2 creerà nuove istanze di RestAdapter ogni volta che le sarà iniettato, penso che faccia esattamente questo, ma non ne sono sicuro.

Spero che questo aiuti!

+0

Grazie a @pratt ci proverò.Ho una domanda, però, non '@ Singleton' dovrebbe creare un solo oggetto per un dato tipo di classe? In questo caso, se annoto entrambi i miei adattatori di riposo come '@ Singleton' (che è di tipo RestAdapter) cosa succederà dietro le quinte? –

+1

Oltre ad annotare il tuo metodo come '@ Singleton', lo stai annotando anche con l'annotazione' @ Named' che dirà a dagger di creare due distinte istanze di RestAdapter per ciascun nome. Assicurati di fare riferimento a quale RestAdapter ti serve usando '@ Named 'come mostrato nella risposta sopra. – Harry

+0

Questo ha senso, grazie. Ci proverò stasera e tornerò da te! –

Problemi correlati