我有以下代码:
SomeClass的
public class SomeClass {
@Inject
@Named("special")
OkHttpClient mOkHttpClient;
public SomeClass(Activity activity) {
((MyApplication) activity.getApplication()).getApplicationComponent().inject(this);
}
}
ApplicationModule
@Module
public class ApplicationModule {
private final Application mApplication;
public ApplicationModule(Application application) {
mApplication = Preconditions.checkNotNull(application);
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
@Provides
@Singleton
SharedPreferences provideCustomSharedPreferences() {
return mApplication.getSharedPreferences("my_custom_file", Context.MODE_PRIVATE);
}
}
ApplicationComponent
@Singleton
@Component(modules = {
ApplicationModule.class,
NetworkModule.class
})
public interface ApplicationComponent {
void inject(SomeClass someClass);
}
MainActivity
public class MainActivity extends AppCompatActivity {
@Inject
SharedPreferences mSharedPreferences;
@Inject
@Named("default")
OkHttpClient mOkHttpClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((MyApplication) getApplication()).getActivityComponent().inject(this);
}
}
NetworkModule
@Module
public abstract class NetworkModule {
private static final int DEFAULT_CACHE_SIZE = 10 * 1024 * 1024; // 10 Mib
@Provides
@Singleton
static Cache provideOkHttpCache(Application application) {
return new Cache(application.getCacheDir(), DEFAULT_CACHE_SIZE);
}
@Provides
@Singleton
@Named("default")
static OkHttpClient provideDefaultOkHttpClient(Cache cache) {
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
// Add logging interceptor here...
}
return okHttpClient.cache(cache).build();
}
@Provides
@Singleton
@Named("special")
static OkHttpClient provideSpecialOkHttpClient(@Named("default") OkHttpClient okHttpClient) {
return okHttpClient.newBuilder()
// Add .certificatePinner() here...
.build();
}
}
ActivityComponent
@Singleton
@Component(modules = {
ApplicationModule.class,
NetworkModule.class
})
public interface ActivityComponent {
void inject(MainActivity mainActivity);
}
所有MyApplication
public class MyApplication extends Application {
private ApplicationComponent mApplicationComponent;
private ActivityComponent mActivityComponent;
@Override
public void onCreate() {
super.onCreate();
}
public ApplicationComponent getApplicationComponent() {
if (mApplicationComponent == null) {
mApplicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
return mApplicationComponent;
}
public ActivityComponent getActivityComponent() {
if (mActivityComponent == null) {
mActivityComponent = DaggerActivityComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
return mActivityComponent;
}
}
但有一些我不喜欢的东西,我知道它们可以通过范围,组件依赖或子组件进行改进。我也可以使用自定义限定符而不是@Named
,但我已经知道了。
这是我想要做的......
我希望provideSpecialOkHttpClient
的范围与SomeClass
生命周期相关联。我知道我需要这个范围......但是这个特殊的OkHttpClient
取决于默认的OkHttpClient
实例,它本身依赖于okhttp3.Cache
实例。最后两个实例是@Singleton
,因为它们可以在任何地方使用。只有特殊的OkHttpClient
实例与SomeClass
相关联,因为它是唯一可以使用它的地方。如何使用范围完成此操作?我的所有尝试都让我犯了错误,因为我在@SomeClassScope
中使用自定义范围,例如@Singleton
和ApplicationComponent
,@Singleton
本身就是Activity
。 简而言之,我怎样才能将一些单例依赖项与应用程序生命周期联系起来,同时让其他依赖项与其他生命周期相关联(如我的示例中的SomeClass
或new ApplicationModule(this)
)是否依赖于单身依赖?
正如您所看到的那样,我两次调用@Singleton
,违背了ActivityComponent
注释组件的目的并提供了方法。如何使ApplicationComponent
依赖于ApplicationModule
,以便我只需在ApplicationComponent
中实例化Response Code : 200
{"message_id": **ID here** }
一次?子?组件依赖?我无法用任何方法完成这项工作......
我很难掌握所有Dagger方面,所以如果你能在回答时提供一些代码示例,那将真正帮助我形象化并理解一切如何联系在一起。
答案 0 :(得分:3)
首先让我们来看看你到目前为止所拥有的东西。 ActivityComponent
有点奇怪。 @Singleton
代表应用程序范围的单例。由于ActivityComponent
会注入具有Activity范围而不是整个app的成员,因此我们可能需要为该Component提供一个新的范围:
@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface PerActivity {}
现在我们可以更改该组件:
@PerActivity
@Component(dependencies = { AppComponent.class
})
public interface ActivityComponent {
void inject(MainActivity mainActivity);
}
请注意,我们现在已将其作为AppComponent
的依赖组件。我们将不得不稍微重构AppComponent
以发布它与依赖组件的绑定。
理由:我们希望ActivityComponent
能够使用OkHttpClient
中绑定的NetworkModule
。但是,NetworkModule
不是ActivityComponent
的模块 - 它是父AppComponent
的一部分。相关组件不会自动"继承父母的所有绑定。为了ActivityComponent
使用OkHttpClient
作为"特殊"的依赖关系。 OkHttpClient
它需要由父组件公开。您可以通过在接口中使用要公开的类型创建方法,将绑定公开给依赖组件。没有必要公开所有绑定,只是那些将在依赖组件中使用的绑定。
@Singleton
@Component(modules = {
ApplicationModule.class,
NetworkModule.class
})
public interface ApplicationComponent {
//injection sites
void inject(SomeClass someClass);
//bindings published to subcomponents
OkHttpClient okHttpClient(); //default
}
现在为"特殊"提取模块。 OkHttpClient
:
@Module
public class SpecialNetworkModule {
@Provides
@PerActivity
@Named("special")
static OkHttpClient provideSpecialOkHttpClient(@Named("default") OkHttpClient okHttpClient) {
return okHttpClient.newBuilder()
// Add .certificatePinner() here...
.build();
}
}
并使用相同的模块撰写ActivityComponent
:
@PerActivity
@Component(modules = { SpecialNetworkModule.class }
dependencies = { AppComponent.class })
public interface ActivityComponent {
void inject(MainActivity mainActivity);
}
SomeClass
基本上属于您的活动范围,因此您可以通过这样做重构它以注入您的活动:
public class SomeClass {
private final Activity activity;
private final OkHttpClient mOkHttpClient;
@Inject
public SomeClass(Activity activity, @Named("special") OKHttpClient client) {
this.activity = activity;
this.mOkHttpClient = client;
}
}
现在让SomeClass
为MainActivity
字段(我假设您在那里使用它,因为它依赖于Activity,它是您提供的唯一活动代码):
@Inject SomeClass someClass
@Override
public void onCreate() {
并确保您的ActivityComponent
提供活动。为此,您需要一个新模块:
@Module
@PerActivity
public class ActivityModule {
private final Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
@Provides
@PerActivity
Activity activity() {
return this.activity;
}
@Provides
@PerActivity
Context context() {
return this.activity;
}
}
使用此模块编写ActivityComponent:
modules = { SpecialNetworkModule.class, ActivityModule.class }
现在组件的消耗需要一点点工作。摆脱应用程序中的public ActivityComponent getActivityComponent()
。 ActivityComponents应该在Activity里面生成,以便它们能够正确地跟踪范围和生命周期。
因此,使用Activity中的组件应该如下所示:
@Inject SomeClass someClass;
@Override
public void onCreate() {
AppComponent appComponent = ((((MyApplication) getApplication()).getActivityComponent());
DaggerActivityComponent.builder()
.appComponent(appComponent)
.activityModule(new ActivityModule(this))
.build()
.inject(this);
}
最后,明确回答你的两个问题:
简而言之,如何将一些单独依赖项与应用程序生命周期联系起来,同时将其他依赖项与其他生命周期(如我的示例中的Activity或SomeClass)相关联,当它们依赖于单例依赖项时?
创建自定义范围(@PerActivity
),跟踪该范围(ActivityComponent
)的组件,并使用单独的模块(SpecialNetworkModule
,ActivityModule
)来缩小范围范围依赖。在这样做时,您需要在更宽范围和更窄范围的组件之间建立某种形式的关系。这可以很好地解决您的下一个问题:
如何使ActivityComponent依赖于ApplicationComponent,以便我只需要在ApplicationComponent中实例化ApplicationModule一次?子?组件依赖?我无法用任何方法完成这项工作......
如上例所示,使用依赖组件(子组件也可以考虑)。在此过程中,请确保更宽范围的组件明确地将其绑定发布到其依赖组件。