Возможно ли использовать элементы @Inject (предоставленные через @Provides), содержащие контекст активности из базовой операции

Хорошо. Позвольте мне попытаться сломать эту ситуацию, потому что я думаю, что это, вероятно, немного непонятно из названия. Прежде чем идти дальше, я скажу, что, насколько это возможно, я попытался основывать основную структуру этого приложения на официальных примерах кинжалов .

По существу, что я пытаюсь сделать, вы можете ввести LocationClient в мою SplashActivity , чтобы установить соединение (через LocationClient.connect() ), как только приложение будет открыто.

Теперь, очевидно, LocationClient не может быть внедрен с помощью любого конструктора по умолчанию (для этого требуются некоторые довольно конкретные вещи (контекст и некоторые обратные вызовы). Итак, я создал @Provides для него в своем ActivityModule :

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

LocationService – это класс, который я создал для реализации обратных вызовов, необходимых для LocationClient . Я также предоставляю это через @Provides в моем ActivityModule :

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

Я дам полный код всех соответствующих файлов в конце этого, для справки.

Итак, я хочу, чтобы @Inject LocationClient на мой SplashActivity . Однако, когда я это делаю, я получаю следующую ошибку:

 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 

Есть только два пути, которые я нашел, чтобы избежать этой ошибки, и ни то, ни другое не нужно. Я могу либо

  1. Переместите инъекцию LocationClient на фрагмент. Это нехорошо, потому что этот момент слишком поздно в потоке процесса приложения. Я хочу, чтобы к этому моменту можно было совершать вызовы в LocationClient , для чего требуется соединение.

  2. Удалите ссылку на контекст активности в @Provides для LocationService и переместите @Provides из ActivityModule в AndroidModule . Это тоже не хорошо, так как мне нужен контекст активности для выполнения некоторых действий в обратных вызовах (как показано в примерах Google для настройки новых служб определения местоположения.

Итак, это дилемма, в которой я застрял. Надеюсь, что это создает некоторое подобие чувства. У меня возникли проблемы с объяснением этого, так как он настолько распространен. Ниже приведен код моего ActivityModule , моего AndroidModule , моего файла приложения и моего 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-модуль

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

Файл приложения

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

Я знаю, что это старый вопрос, но не помните, чтобы комментировать конструктор LocationService с помощью @Inject ?

Кроме того, Logger, необходимый для LocationService, может быть неоднозначным, вам может потребоваться также обеспечить provideLogger чтобы Кинжал мог найти эту зависимость.

Насколько мне известно, возможны только возможные ошибки.