深入浅出Dagger2 : 从入门到爱不释手

Dagger2是什么?

Dagger2是Dagger的升级版,是一个依赖注入框架,第一代由大名鼎鼎的Square公司共享出来,第二代则是由谷歌接手后推出的,现在由Google接手维护.

Github地址

那么,什么是依赖注入?

依赖注入是面向对象编程的一种设计原则,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的.

举个栗子:

    public class ClassA{
        private ClassB b
        public ClassA(ClassB b){
        this.b = b    }
    }

这里ClassA的构造函数里传了一个参数ClassB,随着后续业务增加也许又需要传入ClassC,ClassD.试想一下如果一个工程中有5个文件使用了ClassA那是不是要改5个文件?

这既不符合开闭原则, 也太不软工了.这个时候大杀器Dagger2就该出场了.

  public class ClassA{
     @inject 
      private ClassB b 
      public ClassA(){
       }
    }

通过注解的方式将ClassB b注入到ClassA中, 可以灵活配置ClassA的属性而不影响其他文件对ClassA的使用.

如何使用Dagger2

在实际项目中Dagger2一般和MVP模式配合使用。下面我们先写个简单的Demo体验一下Dagger2.

1.新建一个Demo,模拟登录业务.Model,View,Presenter很简单:

model :

//model 类 
public class User implements Serializable
{
    private int id;
    private String userName;
    private String pwd;

}

//IView类
public interface ICommonView
{
     Context getContext();
}

View :


//activity
public class LoginActivity extends AppCompatActivity implements ICommonView
{


    @BindView(R.id.btn_login)
    Button btn;
  

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        ButterKnife.bind(this);
      

    }


    @OnClick(R.id.btn_login) void login(){
    }

    @Override
    public Context getContext() {
        return this;
    }
}

presenter:

public class LoginPresenter
{
    ICommonView iView;

 
    public LoginPresenter(ICommonView iView){

        this.iView = iView;
    }

    public void login(User user){

        Context mContext = iView.getContext();
        Toast.makeText(mContext,"login......",Toast.LENGTH_SHORT).show();
    }
}

Demo的页面长这样 :
深入浅出Dagger2 : 从入门到爱不释手_第1张图片
登录页面.png

2.导入Dagger2

compile"com.google.dagger:dagger:2.14.1"
annotationProcessor"com.google.dagger:dagger-compiler:2.14.1"

咦?一般的第三方库像Glide,okhttp不都是一行代码引入吗?这里怎么多了一个annotationProcessor?估计用过其他注解框架比如Butterknife,EventBus的同学已经了然了,小白也不要急,后面会讲,先体验一把再说.

2.定义一个注解ActivityScope

  @Scope
  @Retention(RetentionPolicy.RUNTIME)
   public @interface ActivityScope {
   }

这个注解ActivityScope是干啥的?怎么里面啥内容都没有?别急,先放着。

3.创建一个类CommonModule,注意这里用到了刚才定义的@ActivityScope注解

@Module
 public class CommonModule{

    private ICommonView iView;
    public CommonModule(ICommonView iView){
        this.iView = iView;
    }


    @Provides
    @ActivityScope
    public ICommonView provideIcommonView(){
        return this.iView;
    }
  
 }

4.创建一个接口CommonComponent,

  @ActivityScope
  @Component (modules = CommonModule.class)
   public interface CommonComponent {
   void inject(LoginActivity activity); 
   }

5.build一下项目,然后在LoginPresenter里使用@Inject

public class LoginPresenter
{
    ICommonView iView;

    @Inject
    public LoginPresenter(ICommonView iView){

        this.iView = iView;
    }

    public void login(User user){

        Context mContext = iView.getContext();
        Toast.makeText(mContext,"login......",Toast.LENGTH_SHORT).show();
    }
}

6.在LoginActivity中使用CommonComponent接口

public class LoginActivity extends AppCompatActivity implements ICommonView
{


    @BindView(R.id.btn_login)
    Button btn;
    @Inject
    LoginPresenter presenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        ButterKnife.bind(this);
        DaggerCommonCompnent.
                builder().
                commonModule(new CommonModule(this)).
                build().
                Inject(this);

    }


    @OnClick(R.id.btn_login) void login(){

        presenter.login(new User());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    public Context getContext() {
        return this;
    }
}

点击登录按钮后:


深入浅出Dagger2 : 从入门到爱不释手_第2张图片
点击登录按钮.png

达到预期的效果了。

有没有注意到loginPresenter并没有初始化?这里一个重点就是loginPresenter和LoinActivity 解藕了,后续无论怎样修改loginPresenter的构造方法都不需要改动LoinActivity的代码。那要改谁的代码呢?当然是CommonModudle了。

先解释一下上面的几个问题,

annotationProcessor"com.google.dagger:dagger-compiler:2.14.1"是什么情况?

annotationProcessor是处理注解的工具,是APT(Annotation Processing Tool)
的一种,简单来说注解提供的都是一种“标记”,真正使这些“标记”work的是APT,在build的过程中,APT(就是dagger-compiler)扫描到注解(@Component@Module)生成的.这个过程用下面这张图表示:


深入浅出Dagger2 : 从入门到爱不释手_第3张图片
build与apt流程.png

那么apt扫描之后会怎样呢?看一下上面demo的build-->generate-->source-->apt目录下面都有什么:


深入浅出Dagger2 : 从入门到爱不释手_第4张图片
apt文件.png

生成了很多文件。就是apt替我们写了很多类和实现方法。这些文件里面的内容墙裂推荐大家看看。
ActivityScope是干啥的?怎么里面啥内容都没有?

自定义注解ActivityScope作用是限定被它标记的对象生命周期与对应的Activity相同(笑)。其实注解里我们使用了2个元注解
@Scope:标记局部单例;@Retention :指定了它是运行时注解,就是说注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在.
那么,就凭这两个元注解,为啥可以限定被它标记的对象生命周期与对应的Activity相同呢?我们看一下CommonComponent生成类

深入浅出Dagger2 : 从入门到爱不释手_第5张图片
CommonComponent生成类.png

瞅见哪个DoubleCheck了吗?就是说这里是提供了一个provideIcommonViewProvider单例;那这个provideIcommonViewProvider是干啥的呢?再看看这张截图,
image.png

看看LoginPresenter的构造方法就知道provideIcommonViewProvider的作用了。那为啥说提供了provideIcommonViewProvider单例就保证了生命周期和LoginActivity绑定了呢?如果还不明白就想想LoginPresenter的生命周期。
好了,写到这里Dagger2的用法和原理算是“浅出”了,下一篇文章再进行“深入”。

抱歉之前没看明白的各位老铁,文章更新了,尽量写的简介,希望对你们有帮助。

Demo github地址

参考博客:

Dagger2:

https://www.jianshu.com/p/22c397354997

https://www.jianshu.com/p/39d1df6c877d

APT:

https://www.jianshu.com/p/1910762593be

https://blog.csdn.net/Ru_Zhan/article/details/78232851?locationNum=8&fps=1

你可能感兴趣的:(深入浅出Dagger2 : 从入门到爱不释手)