2013-09-10 6 views
5

OK. Pozwólcie, że spróbuję przełamać tę sytuację, ponieważ myślę, że to chyba trochę niejasne z tytułu. Zanim przejdę dalej, powiem, że w miarę możliwości starałem się opierać podstawową strukturę tej aplikacji na official dagger examples.Czy jest możliwe członkostwo @Inject (dostarczone przez @Provides) zawierające kontekst aktywności z podstawowej aktywności

Zasadniczo próbuję wprowadzić LocationClient do mojego SplashActivity, aby nawiązać połączenie (przez LocationClient.connect()) natychmiast po otwarciu aplikacji. .

Teraz, oczywiście, LocationClient nie może być wstrzyknięty poprzez wszelkiego rodzaju domyślnego konstruktora (wymaga to całkiem konkretne rzeczy (kontekst, a niektóre wywołania zwrotne) Więc ja stworzył @Provides za to w moim ActivityModule:

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

LocationService jest klasa I utworzeniu w celu wykonania wywołania zwrotne wymagane przez LocationClient jestem również zapewnienie, że poprzez @Provides w moim ActivityModule.

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

Dostarczę pełny kod wszystkich istotnych plików na końcu tego, dla odniesienia.

Tak, chcę @Inject a LocationClient na mój SplashActivity. Jednak, kiedy to zrobić, pojawia się następujący błąd:

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 

Jest tylko dwa sposoby znalazłem uniknąć tego błędu, a nie osiągnąć to, czego potrzebuję. Mogę albo

  1. Przenieś zastrzyk LocationClient na Fragment. To nie jest dobre, ponieważ punkt ten jest o wiele za późno na przepływ procesu aplikacji. Chcę móc nawiązywać połączenia z numerem LocationClient przez ten punkt, co wymaga nawiązania połączenia.

  2. usunąć odniesienie do kontekstu aktywność w @Provides do LocationService i przesunąć @Provides z ActivityModule do AndroidModule. To również nie jest dobre, ponieważ muszę Context aktywny osiągnąć pewne rzeczy w wywołania zwrotne (jak widać na przykładach Google na tworzenie nowych usług lokalizacyjnych.

Tak, to rodzaj dylematu jestem utknąłem. Mam nadzieję, że to trochę przypomina sens, mam problem z wyjaśnieniem, ponieważ jest tak rozłożony.Poniżej znajduje się kod dla mojego ActivityModule, mój AndroidModule, mój plik aplikacji, a mój 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 Moduł

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

} 

plik Zastosowanie

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

Mam podobną sytuację. Używam klasy LocationService, która używa obiektu LocationClient utworzonego przy użyciu fabryki, i wstawiam usługę LocationService do działania; Usługa LocationService jest również powiązana z cyklem życia aktywności, więc uruchamia/zatrzymuje aktualizacje lokalizacji w onResume i onPause. Używam magistrali zdarzeń (Otto) do wysyłania zdarzenia LocationChangedEvent. Mogę podać kod, nawet jeśli nie jestem pewien, czy jest to właściwe podejście do problemu. – alex

+0

Czy kiedykolwiek to rozgryzłeś? Mam podobny problem. –

Odpowiedz

0

Wiem, że to stare pytanie, ale czy pamiętasz, aby opisać konstruktora usługi LocationService za pomocą @Inject?

Również rejestrator potrzebny do usługi LocationService może być niejednoznaczny, może być potrzebny również provideLogger, aby Dagger mógł zlokalizować tę zależność.

Jedyne możliwe źródła błędu, o ile widzę.