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
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 numeremLocationClient
przez ten punkt, co wymaga nawiązania połączenia.usunąć odniesienie do kontekstu aktywność w
@Provides
doLocationService
i przesunąć@Provides
zActivityModule
doAndroidModule
. 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);
}
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
Czy kiedykolwiek to rozgryzłeś? Mam podobny problem. –