适用于 Android 初学者的 Dagger 2 - 进阶第二部分

原文链接

这个故事是该系列的第七部分,适用于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

系列目录

Dagger 2 前情回顾..

我们采用了一个示例 kickstarter 项目,并尝试使用 Dagger 2 APIs 和注解来解耦和注入依赖项。

我们还看到了 3 个新注解。 一个是 @Scope  - 用于获取单例依赖项。 接下来是 @Named  - 用于区分依赖提供者。 另一个是 @Qualifier 注注解,是 @Named 注解的替代方案,我们看到了两者的实现。

创建多个 Components

到上一章节为止,我们创建了 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 级别的依赖项。 祝贺你自己:-)

如果我们的 Component 中有50个依赖项怎么办?

所以,问题是如果我们有更多的依赖项怎么办?我们需要一直写下面这样的语句吗?

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]

我鼓励反馈,这是学习和重申自己的快速方法。

下一步是什么?

嗯,这是该系列的最后一部分。 如果我遇到其他资源,我肯定会写一下。

您现在可以查看其他资源了,我希望您能理解那些内容 - 因为您将会获得本系列的基础。

参考文献和其他资源

猜你喜欢

转载自blog.csdn.net/qq_33404903/article/details/87927106