原文链接
这个故事是该系列的第七部分,适用于Android 初学者的 Dagger 2。 如果您没有阅读上一个,可以从下面开始。
Dagger 2 for Android Beginners — Introduction
Dagger is a fully static, compile-time dependency injection framework for both Java and Android. It is an adaptation of…medium.com
我们采用了一个示例 kickstarter 项目,并尝试使用 Dagger 2 APIs 和注解来解耦和注入依赖项。
我们还看到了 3 个新注解。 一个是 @Scope
- 用于获取单例依赖项。 接下来是 @Named
- 用于区分依赖提供者。 另一个是 @Qualifier
注注解,是 @Named
注解的替代方案,我们看到了两者的实现。
到上一章节为止,我们创建了 Application
级依赖项。 但是如果我们在 Activity
级别需要一些依赖项呢?由于 Activity
在自己的生命周期中创建和销毁,它的依赖项又如何呢? 因此,在 Activity
中创建的依赖项,应该和 Activity
自身一起被销毁。
这里的最佳实践是,当你将依赖项注入到具有不同生命周期的客户端时,最好为它们创建一个单独的 module 和 component。
在这个例子中,我不想添加其他功能来解释这一点。 相反,让我们将 MainActivity
视为一个单独的要素,并为它创建单独的 module 和 component 。
有关以下更改,请参阅分支 Dagger2Part2
Hariofspades/Dagger-2-Advanced
Dagger-2-Advanced - For the blog : Dagger 2 for Android Beginners - Advancedgithub.com
第1步:创建 Activity 级别的 scope
对于即将进行的更改,在上面的分支中,我已将所有新文件打包在 MainActivityFeature
下。
我们必须为 MainActivity 创建一个新的 Scope。
@Scope
public @interface MainActivityScope {}
第2步:为 MainActivity 创建 Component
现在,让我们使用 MainActivityScope
为 MainActivity
创建一个单独的 Component。
@Component(dependencies = RandomUserComponent.class)
@MainActivityScope
public interface MainActivityComponent {
RandomUserAdapter getRandomUserAdapter();
RandomUsersApi getRandomUserService();
}
正如您在 gist 中注意到的那样,我们需要让 MainActivityComponent
与 RandomUserComponent
进行对话。 因此,我们使用了属性 dependencies
来使它与之对话。 换句话说,它告诉 dagger,如果您需要此 component 的其他依赖项,请查看 RandomUserComponent
。
对于 Activity 级别,对于我们的示例,我们需要 adapter 和 API 调用作为依赖项。 因此,(添加了)方法 getRandomUserAdapter()
和 getRandomUserService()
。
第3步:创建 MainActivity Module
现在让我们为 MainActivity 创建一个 module ,它提供 adapter 依赖。
@Module
public class MainActivityModule {
private final MainActivity mainActivity;
public MainActivityModule(MainActivity mainActivity) {
this.mainActivity = mainActivity;
}
@Provides
@MainActivityScope
public RandomUserAdapter randomUserAdapter(Picasso picasso){
return new RandomUserAdapter(mainActivity, picasso);
}
}
注意:无需通过适配器注入 MainActivity
。这只是举个例子,我正在这样做。如果您需要 Context
用于 Picasso
,您可以使用 holder.imageView.getContext()
。
Notice the scope @MainActivityScope
that we’ve added to randomUserAdapter()
method — to limit the scope within the Activity
.请留意我们已经添加到 randomUserAdapter()
方法的 @MainActivityScope
这个 scope—来限制 Activity
中的 scope。
我们还需要将此 module 映射到其对应的 Component MainActivityComponent
— modules = MainActivityModule.class
链接所有 Components 和 Modules
第4步:创建应用 Application 类
public class RandomUserApplication extends Application {
//在 Manifest 文件中添加 application name
private RandomUserComponent randomUserApplicationComponent;
public static RandomUserApplication get(Activity activity){
return (RandomUserApplication) activity.getApplication();
}
@Override
public void onCreate() {
super.onCreate();
Timber.plant(new Timber.DebugTree());
randomUserApplicationComponent = DaggerRandomUserComponent.builder()
.contextModule(new ContextModule(this))
.build();
}
public RandomUserComponent getRandomUserApplicationComponent(){
return randomUserApplicationComponent;
}
}
此 Application
类包含所有 application 级依赖项 - RandomUserApplicationComponent
。
第5步:修改 MainActivity
如果你点击 build 按钮,Dagger 会为我们创建 DaggerMainActivityComponent
。 使用它,在我们的 MainActivity
中,我们需要获得 Activity 级别的依赖项 - adapter 和 API 服务。
public class MainActivity extends AppCompatActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
....
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.randomUserComponent(RandomUserApplication.get(this).getRandomUserApplicationComponent())
.build();
randomUsersApi = mainActivityComponent.getRandomUserService();
mAdapter = mainActivityComponent.getRandomUserAdapter();
....
}
}
注意:在分支中,查找 afterActivityLevelComponent()
方法
第6步:祝贺你自己
是的。我们已经建立了一些易于管理的代码。 我们已经创建了activity 级别的依赖项。 祝贺你自己:-)
所以,问题是如果我们有更多的依赖项怎么办?我们需要一直写下面这样的语句吗?
randomUserApi = mainActivityComponent.getRandomUserService();
mAdapter = mainActivityComponent.getRandomUserAdapter();
….
你也许并不在乎。 但我知道有人可以为你缩短它。 是的。这就是 @Inject
注解!
使用 @Inject 注解
不必告诉Dagger你需要 RandomUserService 和 RandomUserAdapter,而是让 Dagger 用 @Inject 注解对字段作出反应。
通过如下的少量修改,我们将能够立即使用 @Inject
。 请参考以下分支 InjectMainActivity
Hariofspades/Dagger-2-Advanced
Dagger-2-Advanced - For the blog : Dagger 2 for Android Beginners - Advancedgithub.com
修改 MainActivityComponent
删除方法 getRandomUserService()
和 getRandomUserAdapter()
并添加方法以注入 MainActivity
。
@Component(modules = MainActivityModule.class, dependencies = RandomUserComponent.class)
@MainActivityScope
public interface MainActivityComponent {
void injectMainActivity(MainActivity mainActivity);
}
修改 MainActivity
public class MainActivity extends AppCompatActivity {
....
@Inject
RandomUsersApi randomUsersApi;
@Inject
RandomUserAdapter mAdapter;
....
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
.....
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.randomUserComponent(RandomUserApplication.get(this).getRandomUserApplicationComponent())
.build();
mainActivityComponent.injectMainActivity(this);
....
}
}
这是怎么工作的?好吧,当 Dagger 找到 void 方法-没有返回类型时,它知道类中必须有它需要的东西,即注释了@inject的字段,它将初始化它们。
对!就这样。现在你可以运行代码了!
我们看到了一个关于在 activity 级别创建和注入依赖项的示例。 换句话说,当客户端拥有自己的生命周期时,创建和交互 components。
我们还看到了使用 @Inject
注解来注入 MainActivity 的示例。
感谢您花时间阅读并支持整个系列。 我希望你至少获得了关于 Dependencies 和 Dagger 2 的一些见解。我写这个系列的原因是,我通过阅读许多博客获得了关于 Dagger 2 的知识,但当我向你解释时我获得了更多的见解(写博客)。 因此,我鼓励所有读者以任何可能的方式分享知识。 我不是 Dagger 2 的专家,我认为自己是学习者。 所以,如果你找到了解释这个的更好方法或任何替代方法,请写一个帖子并标记这个系列。
如果您发现任何错误或解释不明确或更好的方法,请写信给我 [email protected]。
我鼓励反馈,这是学习和重申自己的快速方法。
嗯,这是该系列的最后一部分。 如果我遇到其他资源,我肯定会写一下。
您现在可以查看其他资源了,我希望您能理解那些内容 - 因为您将会获得本系列的基础。