2013-09-10 3 views
5

Ok. Lasciatemi provare a rompere questa situazione, perché penso che sia probabilmente un po 'poco chiaro dal titolo. Prima di proseguire, dirò che per quanto possibile, ho cercato di basare la struttura di base di questa app su official dagger examples.E 'possibile i membri @Inject (forniti tramite @Provides), contenenti un contesto di attività dall'attività di base

Essenzialmente quello che sto cercando di fare è essere in grado di iniettare un LocationClient nel mio SplashActivity, in modo da stabilire un collegamento (tramite LocationClient.connect()) non appena si apre l'App. .

Ora, ovviamente, LocationClient non può essere iniettato attraverso qualsiasi tipo di costruttore di default (che richiede alcune cose piuttosto specifici (un contesto, e alcuni callback) Così, ho creato un @Provides per esso nella mia ActivityModule:

@Provides 
@Singleton 
LocationClient providesLocationClient(@ForApplication Context context, LocationService service) { 
    return new LocationClient(context, service, service); 
} 

LocationService è la classe che ho creato per implementare i callback richieste dalla LocationClient sto anche a condizione che attraverso un @Provides nel mio ActivityModule:.

@Provides 
@Singleton 
LocationService providesLocationService(@ForActivity Context context, Logger logger) { 
    return new LocationService(context, logger); 
} 

Fornirò il codice completo di tutti i file rilevanti alla fine di questo, per riferimento.

Quindi, voglio @Inject a LocationClient sul mio SplashActivity. Tuttavia, quando faccio questo, ottengo il seguente errore:

No injectable members on com.google.android.gms.location.LocationClient. Do you want to add an injectable constructor? required by class m.myapp.android.storemode.presentation.activity.SplashActivity 

Ci sono solo due modi che ho trovato per evitare questo errore, e non compiere ciò che mi serve. Posso sia

  1. Spostare l'iniezione di LocationClient su un frammento. Questo non va bene, perché questo punto è troppo tardi nel flusso di processo dell'applicazione. Voglio essere in grado di iniziare a effettuare chiamate allo LocationClient da questo punto, che richiede che sia stata effettuata una connessione.

  2. Rimuovere il riferimento ad un contesto di attività nel @Provides per LocationService, e spostare il @ProvidesActivityModule-AndroidModule. Questo è anche non va bene, perché ho bisogno del contesto di attività per realizzare alcune cose nelle callback (come si è visto negli esempi di Google per la creazione di nuovi servizi di localizzazione.

Quindi, questo è il tipo di dilemma Sono bloccato in. Spero che questo abbia qualche parvenza di senso, ho difficoltà a spiegarlo, dato che è molto diffuso.Di seguito è riportato il codice per il mio ActivityModule, la mia AndroidModule, il mio file di applicazione, e la mia BaseActivity:

ActivityModule

@Module(
    injects = {MainActivity.class, 
       SplashActivity.class, 
       HomeFragment.class, 
       StoreLocatorFragment.class, 
       BrowseProductsFragment.class, 
       BrowseProductCategoriesFragment.class}, 
    includes = {NetworkImageModule.class, ApiModule.class, WatchListModule.class}, 
    complete = false 
) 
public class ActivityModule { 

    private final BaseActivity mActivity; 

    public ActivityModule(BaseActivity activity) { 
     this.mActivity = activity; 
    } 

    /** 
    * Allow the mActivity context to be injected but require that it be annotated with {@link 
    * ForActivity @ForActivity} to explicitly differentiate it from application context. 
    */ 
    @Provides 
    @Singleton 
    @ForActivity 
    Context provideActivityContext() { 
     return mActivity; 
    } 

    @Provides 
    @Singleton 
    KeyboardHider provideKeyboardHider(InputMethodManager imm) { 
     return new KeyboardHider(imm); 
    } 

    @Provides 
    ProgressDialog providesProgressDialog() { 
     return new ProgressDialog(mActivity); 
    } 

    @Provides 
    @Singleton 
    LocationService providesLocationService(@ForActivity Context context, Logger logger) { 
     return new LocationService(context, logger); 
    } 

    @Provides 
    @Singleton 
    LocationClient providesLocationClient(@ForApplication Context context, LocationService service) { 
     return new LocationClient(context, service, service); 
    } 

    @Provides 
    @Singleton 
    PIVenueIdService providesPiVenueIdService(LocationClient locationClient) { 
     return new PIVenueIdService(locationClient); 
    } 

} 

Android modulo

@Module(library = true) 
public class AndroidModule { 

    /** 
    * SharedPreferences name 
    */ 
    public static final String PREFERENCE_NAME = AndroidModule.class 
      .getPackage() 
      .getName() + 
      "Preferences"; 

    private final StoreModeApplication mApplication; 

    //Only created for testing 
    public AndroidModule() { 
     mApplication = null; 
    } 

    public AndroidModule(StoreModeApplication application) { 
     mApplication = checkNotNull(application); 
    } 

    /** 
    * Allow the application context to be injected but require that it be annotated with {@link 
    * ForApplication @Annotation} to explicitly differentiate it from an activity context. 
    */ 
    @Provides 
    @Singleton 
    @ForApplication 
    Context provideApplicationContext() { 
     return mApplication; 
    } 

    @Provides 
    @Singleton 
    SharedPreferences provideSharedPreferences() { 
     return mApplication.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); 
    } 

    @Provides 
    @Singleton 
    RequestQueue provideRequestQueue() { 
     return Volley.newRequestQueue(mApplication); 
    } 

    @Provides 
    @Singleton 
    ActivityManager provideActivityManager() { 
     return (ActivityManager) mApplication.getSystemService(Context.ACTIVITY_SERVICE); 
    } 

    @Provides 
    @Singleton 
    LocationManager provideLocationManager() { 
     return (LocationManager) mApplication.getSystemService(Context.LOCATION_SERVICE); 
    } 

    @Provides 
    @Singleton 
    Logger provideLoggingService() { 
     return new LogCatLogger(); 
    } 

    @Provides 
    @Singleton 
    Gson provideGson() { 
     return new Gson(); 
    } 

    @Provides 
    @Singleton 
    InputMethodManager provideInputMethodManager() { 
     return (InputMethodManager) mApplication.getSystemService(Context.INPUT_METHOD_SERVICE); 
    } 

} 

File di applicazione

public class StoreModeApplication extends Application { 

    private static StoreModeApplication sInstance; 

    private ObjectGraph mGraph; 


    /** 
    * Only use this for easy access to inject function 
    */ 
    public static StoreModeApplication getInstance() { 
     return sInstance; 
    } 

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

     // Setup debugging for butterknife 
     Views.setDebug(BuildConfig.DEBUG); 

     // Create ability to get instance 
     sInstance = this; 

     // Setup DI 
     mGraph = ObjectGraph.create(getModules().toArray()); 


    } 


    /** 
    * Used for injecting dependencies 
    * 
    * @param object object that needs dependencies injected 
    */ 
    public void inject(Object object) { 
     mGraph.inject(object); 
    } 

    /** 
    * Gets mGraph. 
    * 
    * @return Value of mGraph. 
    */ 
    public ObjectGraph getApplicationGraph() { 
     return mGraph; 
    } 

    /** 
    * Creates a list containing all the modules required for dagger 
    */ 
    private List<Object> getModules() { 
     return Arrays.asList(
       new AndroidModule(this), 
       new ActivityObjectMapperModule(), 
       new NetworkImageModule() 
     ); 
    } 

BaseActivity

public abstract class BaseActivity extends Activity { 

    private ObjectGraph mActivityGraph; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     StoreModeApplication storeModeApplication = StoreModeApplication.getInstance(); 
     mActivityGraph = storeModeApplication.getApplicationGraph() 
       .plus(
         getModules().toArray() 
       ); 

     mActivityGraph.inject(this); 
    } 

    @Override 
    protected void onDestroy() { 
     // Eagerly clear the reference to the activity graph to allow it to be garbage collected as 
     // soon as possible. 
     mActivityGraph = null; 
     super.onDestroy(); 
    } 

    protected List<Object> getModules() { 
     return Arrays.asList(
       new ActivityModule(this), 
       new StoreLocatorFragmentModule(), 
       new WatchListModule() 
     ); 
    } 


    /** 
    * Inject the supplied {@code object} using the activity-specific graph. 
    */ 
    public void inject(Object object) { 
     mActivityGraph.inject(object); 
    } 
+1

Ho una situazione simile. Io uso una classe LocationService che utilizza un LocationClient creato usando una factory e io inserisco il LocationService nell'attività; il LocationService è anche legato al ciclo di vita delle attività, quindi avvia/arresta gli aggiornamenti di posizione in onResume e onPause. Io uso un bus eventi (Otto) per inviare un LocationChangedEvent. Posso fornire un codice, anche se non sono sicuro che sia l'approccio giusto al tuo problema. – alex

+0

Lo hai mai capito? Sto avendo un problema simile. –

risposta

0

So che questa è una vecchia domanda ma ti sei ricordato di annotare il costruttore di LocationService con @Inject?

Anche il logger necessario per LocationService potrebbe essere ambiguo, potrebbe anche essere necessario un provideLogger per consentire a Dagger di individuare tale dipendenza.

Le uniche possibili fonti di errore per quanto posso vedere.