美文网首页安卓资源收集安卓开发
安卓dagger2简易使用教程

安卓dagger2简易使用教程

作者: 会飞的大象_ | 来源:发表于2017-12-13 15:11 被阅读34次

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()));

    }

}

运行结果:

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());

    }

}

运行结果:

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());

    }

}

运行结果:

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();

    }

}

运行效果:

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()); }

}

运行效果:

case05 case05-1 case05-2 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());

    }

}

运行结果:

case06

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

Demo 下载地址:demo

相关文章

  • 安卓dagger2简易使用教程

    1.什么是dagger2 dagger2是一个依赖注入框架,依赖注入,我的理解是,一个类中所依赖实例变量,不在本类...

  • dagger2 的安卓支持库的使用

    将以下内容添加到build.gradle中(未包括dagger2基本依赖) 为什么要使用dagger2的安卓支持库...

  • 请仔细阅读教程,按步骤操作!

    苹果安卓通用教程如下:(安卓手机若提示:"GooglePlay服务,vsoc必须搭配使用googlplay服务才能...

  • vsco滤镜获取教程

    苹果安卓通用教程如下:(安卓手机如提示:"GooglePlay服务,vsoc必须搭配使用googlplay服务才能...

  • 恢复滤镜步骤

    苹果安卓通用教程如下:(安卓手机若提示:"GooglePlay服务,vsoc必须搭配使用googlplay服务才能...

  • 电脑挂机教程-基础

    前言: [视频解说]什么是神器评测:神器评测,开启躺赚人生。 [视频教程]使用电脑/安卓手机挂机使用电脑或者安卓手...

  • 进阶篇-每台手机每天5元快速上手完整攻略

    前言: [视频解说]什么是神器评测:神器评测,开启躺赚人生。 [视频教程]使用电脑/安卓手机挂机使用电脑或者安卓手...

  • 安卓 Android Dagger2 学习 使用文档

    安卓 Android Dagger2 学习 使用文档 介绍前,我们先来讲一个故事: 有能力提供保洁和家教服务的人。...

  • Dagger

    神兵利器Dagger2 Android:Dagger2系列2 实例解析(更新完毕) Dagger2 最清晰的使用教程

  • 大疆文档(5)-Android教程-使用UX SDK

    本节全篇为大疆 Mobile SDK 安卓教程 部分,ios教程参见 IOS教程 . 开始使用UX SDK 在本教...

网友评论

    本文标题:安卓dagger2简易使用教程

    本文链接:https://www.haomeiwen.com/subject/bnmgixtx.html