Dagger2的简单使用及解析

Dagger2是什么

Dagger2是一款基于Java注解来实现的完全在编译阶段完成依赖注入的开源库,主要用于模块间解耦、提高代码的健壮性和可维护性。Dagger2在编译阶段通过apt利用Java注解自动生成Java代码,然后结合手写的代码来自动帮我们完成依赖注入的工作。

不用Dagger2的代码

public class Student {
    String name = "liu";
    Student() {
    }
}

有个Student类, 我需要在多个Activity中都创建这个类的对象。需要这么写:

public class MainActivity extends AppCompatActivity {  
    Student student;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        student = new Student();
    }
}
public class MainActivity2 extends AppCompatActivity {  
    Student student;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        student = new Student();
    }
}
public class MainActivity3 extends AppCompatActivity {  
    Student student;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        student = new Student();
    }
}

如果我的Student的构造方法改了,改成有参构造。传了个int,如下所示,那么我需要在每个用到构造方法的地方,都修改一次。有点痛苦, 三个用到的还可以,改改就是了,但是要是二三十个用到了,那真是太难了。

public class Student {
    String name = "liu";
    int age;
    Student(int age) {
    	this.age=age;
    }
}

使用Dagger2的时候

public class MainActivity extends AppCompatActivity {

    @Inject
    Student student;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerStudentComponent.create().injectMainActivity(this);
    }
}
public class MainActivity2 extends AppCompatActivity {

    @Inject
    Student student;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerStudentComponent.create().injectMainActivity(this);
    }
}
public class MainActivity3 extends AppCompatActivity {

    @Inject
    Student student;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerStudentComponent.create().injectMainActivity(this);
    }
}

就这么一写, Student的对象就初始化完成了, 具体是由下面这个来决定如何构造Student对象的。

@Module
public class StudentModule {

    @Provides
    public Student getStudent() {
        return new Student(99);
    }

}

@Component(modules = StudentModule.class)
public interface StudentComponent {

    // 送到收货地址 --- 注入到Activity
    void injectMainActivity(MainActivity mainActivity);

    void injectMainActivity(MainActivity2 mainActivity);

    void injectMainActivity(MainActivity3 mainActivity);

    void injectMainActivity(MainActivity4 mainActivity);

}

逻辑梳理

Dagger2的简单使用及解析_第1张图片
如上面这个购物的例子。买家在网上下单, 然后卖家将商品打包好,交给快递员,快递员将快递送给买家。什么样的东西用什么样的包裹,但是快递员是不知道包裹里面是什么的, 买家也不需要知道商品是怎么生产的,用就完事了。

代码流程

注入的起点是DaggerStudentComponent.create().injectMainActivity(this);这个代码。DaggerStudentComponent这个类是根据@Component(modules = StudentModule.class)注解动态生成的。DaggerStudentComponent这个类会实现有这个注解的接口

@Component(modules = StudentModule.class) // 快递员拿到了包裹
public interface StudentComponent {

    // 送到收货地址 --- 注入到Activity
    void injectMainActivity(MainActivity mainActivity); // 不支持多态功能的

    void injectMainActivity(MainActivity2 mainActivity);

    void injectMainActivity(MainActivity3 mainActivity);

    void injectMainActivity(MainActivity4 mainActivity);

}

再看DaggerStudentComponent.create()方法做了什么

  public static StudentComponent create() {
    return builder().build();
  }

通过build设计模式构造了StudentComponent 的具体对象。Build的类如下所示。

 public static final class Builder {
    private StudentModule studentModule;

    private Builder() {}

    public StudentComponent build() {
      if (studentModule == null) {
        this.studentModule = new StudentModule();
      }
      return new DaggerStudentComponent(this);
    }

    public Builder studentModule(StudentModule studentModule) {
      this.studentModule = Preconditions.checkNotNull(studentModule);
      return this;
    }
  }

所以DaggerStudentComponent.create()方法就是构造了DaggerStudentComponent这个对象。而构造方法中进行了一些变量的初始化

  private DaggerStudentComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }
private void initialize(final Builder builder) {

    this.getStudentProvider = StudentModule_GetStudentFactory.create(builder.studentModule);

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(getStudentProvider);

    this.mainActivity2MembersInjector = MainActivity2_MembersInjector.create(getStudentProvider);

    this.mainActivity3MembersInjector = MainActivity3_MembersInjector.create(getStudentProvider);
  }

这其中就有几个注射器和一个Student提供者,这里先知道这几个变量在构造方法的时候初始化的。后面再详细分析。

再看DaggerStudentComponent.create().injectMainActivity(this);injectMainActivity方法。实际上这个方法是从StudentComponent接口中实现的。

  @Override
  public void injectMainActivity(MainActivity mainActivity) {
    mainActivityMembersInjector.injectMembers(mainActivity);
  }

注射到MainActivity,就是使用了mainActivityMembersInjector这个注射器的injectMembers方法,如下所示:

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.student = studentProvider.get();
  }

如果传进来的MainActivity对象为空,则抛出异常,否则mainactivity.student = studentProvider.get();

studentProvider.get();的具体实现是交由module来实现的

@Override
  public Student get() {
    return Preconditions.checkNotNull(
        module.getStudent(), "Cannot return null from a non-@Nullable @Provides method");
  }

这个module也就是我们自己定义的。

@Module
public class StudentModule {

    @Provides
    public Student getStudent() {
        return new Student(99);
    }

}

终于我们MainActivity.student这个变量有了值了。

具体实现

先看一下几个动态的类是怎么来的。
Dagger2的简单使用及解析_第2张图片

Dagger2的简单使用及解析_第3张图片

Dagger2的简单使用及解析_第4张图片

Component将需要Student对象的 对象传给Injector,Injector找Provides要Student对象赋值给student变量。

总结

的确实现了实体与Activity之间的解耦,使用起来也挺方便的。 但是就是编译会比较慢了,需要在编译器生成多个文件,最终也会增加大apk。

你可能感兴趣的:(android)