dagger2学习

来源:互联网 发布:信仰的定义知乎 编辑:程序博客网 时间:2024/05/16 14:52

最近在学习单元测试的过程中,学习一下使用dagger2来做依赖注入

在介绍dagger2的使用前,先来介绍一下DL的几种方式。

  1. set方法
  2. 将依赖作为参数
  3. 将依赖作为构造方法的参数传入(推荐使用这种方式)

下面重点介绍dagger2的使用

1.定义

ModuleDependency生产工厂

一个Module对应代码中的一个类,同时为了表示这是一个Module,而不是一个简单的类,需要添加dagger2里面的一个annotation @Module来进行标识,之所以说Module是一个生产dependency的工厂,是因为Module中有很多方法,而这些方法主要是创建dependency,但是一个Module就是一个类,他里面也有正常的方法,而为了区别哪些是用来创建dependency的方法,需要用dagger2里面的一个annotation @Provides来加以区分。具体实例代码如下:

@Modulepublic class AppModule {    @Provides    public LoginPresenter provideLoginPresenter(UserManager userManager){        return new LoginPresenter(userManager);    }    @Provides    public UserManager provideUserManager(){        return new UserManager();    }    @Provides    public PassWordValidator providePassWordValidator(){        return new PassWordValidator();    }}

例如创建一个LoginPresenter对象,会先到module中寻找Loginpresenterprovide方法,这时发现创建LoginPresenter对象需要传入一个UserManager对象,就会在Module中继续寻找UserManagerProvide方法,再调用LoginPresenterProvide方法创建LoginPresenter对象

ComponentDependency生产工厂管理员

Component是一个接口,和Module需要使用@Module一样,也是需要使用@Component来修饰,表示这是一个dagger2Component,实际使用中,由于有多个Module以及Component,我们需要告知Component去哪些Module中寻找Provide方法,这时我们的Component就可以定义为:

@Component(modules = {AppModule.class})  //<=    public interface AppComponent {}

其中modules属性接收一个数组,里面是这个Component管理的所有Module

2.使用

方法一:在Component中定义一个Dependency的返回方法

例如我们需要一个Loginpresenter,我们就可以在Component中定义一个Loginpresenter的返回方法,如下:

@Component(modules = {AppModule.class})public interface AppComponent {    LoginPresenter loginPresenter();}

了解完使用方法以后,我们来了解一下dagger2的工作原理,在你的java代码编译成字节码的过程中,dagger2会对所有的Component(就是用 @Component修饰过的interface进行处理,自动生成一个实现了这个interface的类,生成的类名是Component的名字前面加上Dagger,比如我们定义的 AppComponent,对应的自动生成的类叫做DaggerAppComponent。我们知道,实现一个interface需要实现里面的所有方法,因此,DaggerAppComponent是实现了 loginPresenter()这个方法的。实现的方式大致就是从 AppComponent管理的 AppModule里面去找LoginPresenterProvider方法,然后调用这个方法,返回一个LoginPresenter

因此,使用这种方式,当Client需要Dependency的时候,首先需要用DaggerAppComponent这个类创建一个对象,然后调用这个对象的loginPresenter()方法,这样Client就能获得一个LoginPresenter了,这个DaggerAppComponent对象的创建及使用方式如下:

public class MainActivity extends AppCompatActivity {    LoginPresenter mLoginPresenter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule()).build();        LoginPresenter presenter = appComponent.loginPresenter();    }}

方法二:使用Field Injection

使用这种方式的做法是,我们就在LoginActivity里面定义一个LoginPresenterfield,这个field需要使用@Inject修饰一下,然后在onCreate()里面,我们把DaggerAppComponent对象创建出来,调用这个对象的inject方法,把LoginActivity传进去

public class LoginActivity extends AppCompatActivity {    @Inject    LoginPresenter mLoginPresenter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule()).build();        appComponent.inject(this);    }}

当然,我们需要先在AppComponent里面定义一个inject(LoginActivity loginActivity)方法:

@Component(modules = {AppModule.class})public interface AppComponent {    void inject(LoginActivity loginActivity);}

需要注意的是,@Inject field不能使用private,不然dagger2找不到这个field。不过,需要注意的一点是,这种方式不支持继承,比如说LoginActivity继承自一个 BaseActivity,而@Inject StatManager mStatManager是放在BaseActivity里面的,那么在LoginActivity里面调用 appComponent.inject(this),并不会让BaseActivity里面的 mStatManager得到实例化,你必须在 BaseActivity里面也调用一次appComponent.inject(this);

其他注解标识@SingletonConstructor Injection

如果每次ClientComponent索要一个DependencyComponent都会创建一个新的出来,这可能会导致资源的浪费,或者说很多时候不是我们想要的,比如说,SharedPreferencesUserManagerOkHttpClient, Retrofit这些都只需要一份就好了,不需要每次都创建一个instance,这个时候我们可以给这些DependencyProvider方法加上@Singleton就好了

@Modulepublic class AppModule {    @Provides    @Singleton              public OkHttpClient provideOkHttpClient() {        OkHttpClient okhttpClient = new OkHttpClient.Builder()                .connectTimeout(30, TimeUnit.SECONDS)                .build();        return okhttpClient;    }}

其实AppModule里面的很多Provider方法是不需要定义的。比如说在这种情况下,LoginPresenterProvider方法 provideLoginPresenter(UserManager userManager)就不需要定义,你只需要在定义LoginPresenter的时候,给它的Constructor加上 @Inject修饰一下,这也就是我们现在要讨论的Constructor Injection

public class LoginPresenter {    UserManager mUserManager;    @Inject    public LoginPresenter(UserManager userManager) {        mUserManager = userManager;    }    public void login(String name, String pwd){        if (name==null||name.length()==0){return;}        if (pwd==null||pwd.length()==0){return;}        mUserManager.performLogin(name,pwd);    }}

dagger2会自动创建这个LoginPresenter所需要的Dependency,所以会去Module里面找到这个LoginPresenter所需的Dependency,交给LoginPresenterConstructor,创建好这Dependency,交给Client,同理我们也不需要提供UserManagerProvider方法,只需要在它的构造方法上添加@Inject。说白了,你只需要给那些不是通过Constructor来创建的Dependency(比如说SharedPreferencesUserApiService等)定义Provider方法。

参考文章

使用dagger2来做依赖注入,以及在单元测试中的应用

原创粉丝点击