美文网首页安卓资源收集安卓开发
安卓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简易使用教程

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