安卓dagger2简易使用教程

1. 什么是dagger2

dagger2是一个依赖注入框架,依赖注入,我的理解是,一个类中所依赖实例变量,不在本类中直接创建,而是在其他类中赋值然后传入。

权威解释:依赖注入


2.为什么使用dagger2

dagger2设计的目的就是为了解耦合,避免了一个类中各种眼花缭乱、重复的赋值语句。


3.如何使用dagger2

dagger2使用正确步骤:导入依赖→编写代码↔rebuild工程(根据注解自动生成中间代码)→开始运行

dagger2使用官方教程:https://google.github.io/dagger/

dagger2 gitub:https://github.com/google/dagger

3.1.导入依赖

1.在gradle的buildscript下:

dependencies { ...

//添加apt插件 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

}

2.在build.gradle中:

apply plugin: 'com.neenbedankt.android-apt'

...

dependencies {

apt 'com.google.dagger:dagger-compiler:2.4'

compile 'com.google.dagger:dagger:2.4'

//java注解 provided 'org.glassfish:javax.annotation:10.0-b28'

}

3.2.代码编写

3.2.1.Componet + Inject

Componet组件:连接目标类和赋值类的桥梁,使用@Componet注解在对应组件类的类名前标注

Inject:说明目标类属性和赋值类赋值方法的位置,使用@Inject注解在对应类的构造方法前进行标注

赋值类:

1.使用Inject来赋值,只能使用构造标注,不能使用方法标注

//正确的用法

public class IntegerProducer {

    private int num;

    @Inject 

    public IntegerProducer() {

        num = new Random().nextInt(9999);

    }

    public int produce() {

        return num;

    }

}

//错误的用法(以下用法编译不通过)

public class OtherProducer {

    @Inject

    public IntegerProducer get() {

        return new IntegerProducer();

    }

}

2.带参的构造方法,其参数应该也可以依赖注入

public class FatherProducer {

private IntegerProducer ip;

    @Inject // IntegerProducer 已经支持依赖注入,可以参照上面的例子

    public FatherProducer(IntegerProducer ip) {

    this.ip = ip;

    }

    public int produce() {

        return ip.produce();

    }

}

3.一个Inject赋值类中只能提供一个赋值构造方法,也就是说只能有一个@Inject注解标注的构造函数

桥梁:

1.使用interface定义,在接口前使用@Component注解标注

2.接口内方法必须提供与目标类绑定或者关联的方法

@Component

public interface Case01Component {

    void inject(Case01Activity activity);

}

目标类:

1.在目录类属性前使用@Inject注解

2.待注入的属性值不能用private修饰

public class Case01Activity extends AppCompatActivity {

    @Inject

    IntegerProducer ip;

    @Inject

    FatherProducer fp;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case01);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

        DaggerCase01Component.builder().build().inject(this);  // DaggerCase01Component是根据Component桥梁的代码,然后rebuild工程生成的

    }

    public void test(View v) {

        line1.setText(String.valueOf(ip.produce()));

        line2.setText(String.valueOf(fp.produce()));

    }

}

运行结果:


安卓dagger2简易使用教程_第1张图片
case-01

3.2.2.Component + Module

Module注解:Module的功能和Inject类似,也是用作赋值功能,使用@Module注解在Moudle类前标注

1.Module中提供赋值类的办法是,在方法上添加@Provides注解

@Module

public class Case02Module {   

     @Provides    

    public ColorPicker provideColorGreen() {        

        return new ColorPicker(Color.GREEN);    

    }

}

2.Component需与对应的Module关联起来(注:一个Component可与多个Module关联起来)

@Component(modules = Case02Module.class)

public interface Case02Component {

    void inject(Case02Activityactivity);

}

3.目标类属性依然使用@Inject标注

public class Case02Activity extends AppCompatActivity {

    @Inject

    ColorPicker cp;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case02);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

    }

    public void test(View v) {

        line1.setTextColor(cp.pick());

        line2.setTextColor(cp.pick());

    }

}

运行结果:


安卓dagger2简易使用教程_第2张图片
case-02


4.一个Module中对于同一种赋值类,可以使用@Named注解提供多钟赋值方法(与@Inject赋值的区别之一)

@Module

public class Case02Module {

    @Provides

    @Named("green")

    public ColorPicker provideColorGreen() {

        return new ColorPicker(Color.GREEN);

    }

    @Provides

    @Named("blue")

    public ColorPicker provideColorBlue() {

        return new ColorPicker(Color.BLUE);

    }

}


public class Case02Activity extends AppCompatActivity {

    @Inject

    @Named("green")

    ColorPicker cp1;

    @Inject

    @Named("blue")

    ColorPicker cp2;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case02);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) finViewById(R.id.line2);

        DaggerCase02Component.builder().build().inject(this);

    }

    public void test(View v) {

        line1.setTextColor(cp1.pick());

        line2.setTextColor(cp2.pick());

    }

}

运行结果:


安卓dagger2简易使用教程_第3张图片
case-02.1


5.Module赋值和Inject赋值同时存在时,先查找Module,如果Module赋值成功,不再查找Inject注解;如果Module赋值不成功,继续查找Inject赋值

3.2.3.作用域Scope

作用域:限定赋值方法的使用范围

1.作用域如何自定义,类似于自定义注解,除此之外要加@Scope注解

@Scope

@Retention(RetentionPolicy.RUNTIME)

public @interface Color {}


@Scope

@Retention(RetentionPolicy.RUNTIME)

public @interface Content {}

2.作用域,限定了Component能使用哪些赋值方法

a)Componet和Module中赋值方法通过同一个作用域标注@Content联结起来,如何缺少Module中赋值方法的作用域,则会编译错误

@Module

public class Case03Module {

    @Content

    @Provides

    public IntegerProducer produceNum() {

        return new IntegerProducer();

    }

}

@Content

@Component(modules = Case03Module.class)

public interface Case03Component {

    void inject(Case03Activity activity);

}


b)有趣的是,Component可以同时有多个作用域,类似以下例子@Content @Color

@Module

public class Case03Module {

    @Content

    @Provides

    public IntegerProducer produceNum() {

        return new IntegerProducer();

    }

    @Color

    @Provides

    public ColorPicker produceColor() {

       return new ColorPicker(android.graphics.Color.RED);

    }

}

@Content

@Color

@Component(modules = Case03Module.class)

public interface Case03Component {

    void inject(Case03Activity activity);

}

3.不加作用域,赋值时会生成新的变量

@Component(modules = Case04Module.class)

public interface Case04Component {

    void inject(Case04Activity activity);

}

@Module

public class Case04Module {

    @Provides

    public AddressProducer provideAddress() {

        return new AddressProducer();

    }

}

public class Case04Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    @Inject

    AddressProducer ap2;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case04);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

        DaggerCase04Component.builder().build().inject(this);

    }

    public void test(View v) {

        line1.setText(ap1.produce());

        line2.setText(ap2.produce());

    }

}

public class AddressProducer {

    public AddressProducer() { }

    public String produce() { return this.toString();

    }

}

运行效果:


安卓dagger2简易使用教程_第4张图片
case04

4.@Singleton标注一般用来做全局单例,实质上是没有直接使赋值变量成为单例的能力,以下例子可以看出其实注入的属性值是不是同一个,取决于是否为同一个Component注入;因此要想保持全局单例,正确的做法应该是在Application或者BaseActivity基类中去初始化Component,然后在Appliaction或者基类容器缓存单例Component,然后再其他地方去注入或者联结

@Component(modules = Case05Module.class)

@Singleton

public interface Case05Component {

    void inject(Case05Activity activity);

    void inject(Case051Activity activity);

    void inject(Case052Activity activity);

    void inject(Case053Activity activity);

}

@Module

public class Case05Module {

    @Provides

    @Singleton

    public AddressProducer provideAddress() {

        return new AddressProducer();

    }

}

public class Case05Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    @Inject

    AddressProducer ap2;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case05);

        //因为是使用同一个实例化的Component注入,两个变量相等       

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

        DaggerCase05Component.builder().build().inject(this);

    }

    public void test(View v) {

        line1.setText(ap1.produce());

        line2.setText(ap2.produce());

    }

}

public class Case051Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    private TextView line1;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case051);

    line1 = (TextView) findViewById(R.id.line1);

    DaggerCase05Component.builder().build().inject(this);

    }

    public void test(View v) {

        line1.setText(ap1.produce());

    }

}


public class App extends Application {

    private Case05Component case05Component;

    @Override

    public void onCreate() {

        super.onCreate();

        case05Component = DaggerCase05Component.builder().build();

    }

    public Case05Component getCase05Component() { return case05Component; }

}


public class Case052Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    private TextView line1;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case052);

        line1 = (TextView) findViewById(R.id.line1);

        App app = (App) getApplicationContext();

        app.getCase05Component().inject(this);

}

    public void test(View v) { line1.setText(ap1.produce()); }

}


public class Case053Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    private TextView line1;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case053);

        line1 = (TextView) findViewById(R.id.line1);

        App app = (App) getApplicationContext();

        app.getCase05Component().inject(this);

}

    public void test(View v) { line1.setText(ap1.produce()); }

}

运行效果:


安卓dagger2简易使用教程_第5张图片
case05


安卓dagger2简易使用教程_第6张图片
case05-1


安卓dagger2简易使用教程_第7张图片
case05-2


安卓dagger2简易使用教程_第8张图片
case05-3

5.自定义作用域名义上是局部作用域,实质上和@Singleton一样是没有真正的限定使用范围的功能,还是通过缓存实例化的Component来达到真正的作用域功能

@Scope

@Retention(RetentionPolicy.RUNTIME)

public @interface address {}



@Component(modules = Case06Module.class)

@address

public interface Case06Component {

    void inject(Case06Activity activity);

    void inject(Case061Activity activity);

}


@Module

public class Case06Module {

    @Provides

    @address

    public AddressProducer provideAddress() {

        return new AddressProducer();

    }

}


public class Case06Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    @Inject

    AddressProducer ap2;

    private TextView line1;

    private TextView line2;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case05);

        line1 = (TextView) findViewById(R.id.line1);

        line2 = (TextView) findViewById(R.id.line2);

        DaggerCase06Component.builder().build().inject(this);

    }

    public void test(View v) {

        line1.setText(ap1.produce());

        line2.setText(ap2.produce());

    }

}


public class Case061Activity extends AppCompatActivity {

    @Inject

    AddressProducer ap1;

    private TextView line1;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_case061);

        line1 = (TextView) findViewById(R.id.line1);

        DaggerCase06Component.builder().build().inject(this);

    }

    public void test(View v) {

        line1.setText(ap1.produce());

    }

}

运行结果:


安卓dagger2简易使用教程_第9张图片
case06


安卓dagger2简易使用教程_第10张图片

End:有关dagger2的简易使用教程,暂时就介绍到这里,有时间继续补充其他使用案例和原理,如果你发现了错误,欢迎批评与指正。

Demo 下载地址:demo

你可能感兴趣的:(安卓dagger2简易使用教程)