Dagger2与MVP(八)

Dagger2与MVP(八)

前面介绍了Dagger2的基本知识,并且通过示例代码演示了如何在Android开发中去使用Dagger2
Dagger2可以减少很多模板化的代码,更易于测试、降低耦合度,创建可复用可交换的模板。

Dagger2优点:

  • 提供了对全局对象实例的简单访问方式
    声明了单例的实例都可以通过@Inject进行访问。比如下面的MyTwitterApiClientSharedPreferences的实例:

    public class MainActivity extends Activity {
       @Inject MyTwitterApiClient mTwitterApiClient;
       @Inject SharedPreferences sharedPreferences;
    
       public void onCreate(Bundle savedInstance) {
           // assign singleton instances to fields
           InjectorClass.inject(this);
       }
    }
  • 复杂的依赖关系只需要简单的配置
    Dagger2会通过依赖关系并且生成易懂易分析的代码。以前通过手写的大量模板代码中的对象引用将会由它给你创建并传递到相应对象中。
    因此你可以更多的关注模块中构建的内容而不是模块中的对象实例的创建顺序。

  • 作用域实例
    我们不仅可以轻松的管理全局实例对象,也可以使用Dagger2中的scope定义不同的作用域。(比如根据user sessionactivity的生命周期)

在之前写的一篇文章Android开发中的MVP模式详解中,讲到了Google官方的android-architecture,下面就从前面这篇文章的基础往下说。android-architecture里面有一个分支是todo-mvp-daggerMVPDagger2搭配,开发不累。

我们在没使用dagger之前,进行mvp开发的时候,是不是需要创建viewpresenter啊,然后让他俩分别持有对方的对象。
那使用dagger后该怎么实现呢?

Dagger2与MVP(八)_第1张图片

我们可以看到和之前的区别就是:

  • 多了di包,这里面都是动态注入相关的类:有全局的ApplicationModuleAppComponentActivityBindingModule和自定义的Scope
  • 每个页面都多了一个对应的XXXModule

  • 然后ToDoApplication实现了DaggerApplication

就从ToDoApplication开始分析吧:

public class ToDoApplication extends DaggerApplication {
    @Inject
    TasksRepository tasksRepository;

    @Override
    protected AndroidInjector applicationInjector() {
        return DaggerAppComponent.builder().application(this).build();
    }

    /**
     * Our Espresso tests need to be able to get an instance of the {@link TasksRepository}
     * so that we can delete all tasks before running each test
     */
    @VisibleForTesting
    public TasksRepository getTasksRepository() {
        return tasksRepository;
    }
}

继承DaggerApplication并且实现applicationInjector方法,这是为了让Activity不用每个都去调用componentinject方法。
这里用到了TasksRepositoryAppComponent,我们去看一下AppComponent:

@Singleton
@Component(modules = {TasksRepositoryModule.class,
        ApplicationModule.class,
        ActivityBindingModule.class,
        AndroidSupportInjectionModule.class})
public interface AppComponent extends AndroidInjector<ToDoApplication> {
    // 提供TaskRepository的注入对象
    TasksRepository getTasksRepository();

    // Gives us syntactic sugar. we can then do DaggerAppComponent.builder().application(this).build().inject(this);
    // never having to instantiate any modules or say which module we are passing the application to.
    // Application will just be provided into our app graph now.
    @Component.Builder
    interface Builder {

        @BindsInstance
        AppComponent.Builder application(Application application);

        AppComponent build();
    }
}

这里面会将TasksRepositoryModuleApplicationModuleActivityBindingModule都进行绑定。

@Module
public abstract class ApplicationModule {
    //expose Application as an injectable context
    @Binds
    abstract Context bindContext(Application application);
}

@Module
public abstract class ActivityBindingModule {
    // 注意下面的这四个`Module`
    @ActivityScoped
    // TasksModule是给`TasksActivity`提供注入对象的
    @ContributesAndroidInjector(modules = TasksModule.class)
    abstract TasksActivity tasksActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = AddEditTaskModule.class)
    abstract AddEditTaskActivity addEditTaskActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = StatisticsModule.class)
    abstract StatisticsActivity statisticsActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = TaskDetailPresenterModule.class)
    abstract TaskDetailActivity taskDetailActivity();
}

TasksRepositoryModule是在Mock中:

/**
 * This is used by Dagger to inject the required arguments into the {@link TasksRepository}.
 */
@Module
abstract public class TasksRepositoryModule {

    private static final int THREAD_COUNT = 3;

    @Singleton
    @Binds
    @Local
    abstract TasksDataSource provideTasksLocalDataSource(TasksLocalDataSource dataSource);

    @Singleton
    @Binds
    @Remote
    abstract TasksDataSource provideTasksRemoteDataSource(FakeTasksRemoteDataSource dataSource);

    @Singleton
    @Provides
    static ToDoDatabase provideDb(Application context) {
        return Room.databaseBuilder(context.getApplicationContext(), ToDoDatabase.class, "Tasks.db")
                .build();
    }

    @Singleton
    @Provides
    static TasksDao provideTasksDao(ToDoDatabase db) {
        return db.taskDao();
    }

    @Singleton
    @Provides
    static AppExecutors provideAppExecutors() {
        return new AppExecutors(new DiskIOThreadExecutor(),
                Executors.newFixedThreadPool(THREAD_COUNT),
                new AppExecutors.MainThreadExecutor());
    }
}

这是用于mock测试的一个类,里面的两个方法分别表示本地数据和远程数据,最终返回的都是TasksDataSourcemock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。这里对于数据对象直接在这里进行初始化,而不是在所有的用到该数据的地方new一遍。这也就体现了Dagger2的引入对测试是一个极大的便利。

上面看到了ActivityBindingModule中对每个Activity都声明的Module,接下来就看TasksModule:

/**
 * This is a Dagger module. We use this to pass in the View dependency to the
 * {@link TasksPresenter}.
 */
@Module
public abstract class TasksModule {
    @FragmentScoped
    @ContributesAndroidInjector
    abstract TasksFragment tasksFragment();

    @ActivityScoped
    @Binds abstract TasksContract.Presenter taskPresenter(TasksPresenter presenter);
}

这里面分别提供了对应ViewFragment以及对应Presenter


更多文章请查看AndroidNote

你的star是我的动力!!!

你可能感兴趣的:(Android,Dagger2学习教程)