美文网首页Android 流行技术Android技术知识Android开发
dagger2 循序渐进学习(包会)(二)

dagger2 循序渐进学习(包会)(二)

作者: 张哲1111 | 来源:发表于2017-02-17 22:06 被阅读160次

    文章索引
    dagger2 循序渐进学习(一)依赖注入基础知识(包会)
    dagger2 循序渐进学习(二)
    dagger2 循序渐进学习(三) 实例1,application中的应用

    昨天写了关于dagger2 的重要但比较易于理解的基础知识 依赖注入,这里是链接dagger2 循序渐进学习(一)依赖注入基础知识
    今天这篇就开始主要讲dagger2 本身了,遵循循序渐进简单易懂的原则,所以要花费一定篇幅。

    那么首先要明确了解一下dagger2是什么:
    Dagger1
    这个版本不是这篇文章的重点,所以我只是简略地说一下。不管怎样,Dagger1还是做了很多的贡献,可以说是如今Android上最流行的依赖注入框架。它是由Square公司受到Guice启发创建的。
    基本特点:
    多个注入点:依赖,通过injected
    多种绑定方法:依赖,通过provided
    多个modules:实现某种功能的绑定集合
    多个对象图: 实现一个范围的modules集合

    Dagger1是在编译的时候实行绑定,不过也用到了反射机制。但这个反射不是用来实例化对象的,而是用于图的构成。Dagger会在运行的时候去检测是否一切都正常工作,所以使用的时候会付出一些代价:偶尔会无效和调试困难。
    Dagger2
    Dagger2是Dagger1的分支,由谷歌公司接手开发,目前的版本是2.0。Dagger2是受到AutoValue项目的启发。 刚开始,Dagger2解决问题的基本思想是:利用生成和写的代码混合达到看似所有的产生和提供依赖的代码都是手写的样子。
    如果我们将Dagger2和1比较,他们两个在很多方面都非常相似,但也有很重要的区别,如下:
    再也没有使用反射:图的验证、配置和预先设置都在编译的时候执行。
    容易调试和可跟踪:完全具体地调用提供和创建的堆栈
    更好的性能:谷歌声称他们提高了13%的处理性能
    代码混淆:使用派遣方法,就如同自己写的代码一样

    当然所有这些很棒的特点都需要付出一个代价,那就是缺乏灵活性,例如:Dagger2没用反射所以没有动态机制。

    是不是蒙蔽了😓!!
    废话少说,上代码,来看下如何找Android 中使用dagger2。
    首先在整个项目的gradle文件中加入即时编译生成代码的apt插件依赖(或者也可以写到下面moudel的gradle文件中)

    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    
    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:2.2.3'
            classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'//这里是添加的,也可以写到下面moudel的gradle文件中
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
        }
    }
    
    allprojects {
        repositories {
            jcenter()
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
    

    然后在moudel的gradle文件中加入相关依赖:

    apply plugin: 'com.android.application'
    apply plugin: 'com.neenbedankt.android-apt' //加入即时编译插件apt
    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.2"
        defaultConfig {
            applicationId "zhangzhe.daggerdemo"
            minSdkVersion 15
            targetSdkVersion 25
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
        compile 'com.android.support:appcompat-v7:25.1.0'
        testCompile 'junit:junit:4.12'
    
        apt 'com.google.dagger:dagger-compiler:2.0'//这里是添加的
        compile 'com.google.dagger:dagger:2.0'//这里是添加的
        provided 'javax.annotation:jsr250-api:1.0'//这里是添加的
    }
    

    先不讲dagger2的理论一些名称直接撸代码;
    以Android当前流行的mvp模式为例,写一个简要的登录demo。

    1.先建立登录的activity 作为view层;

    public class LoginActivity extends AppCompatActivity  {
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
      
    }
    }
    

    2.建立ILoginContract协议接口,定义view层和presenter层的逻辑。

    public interface ILoginContract {
    interface ILoginPresenter {
        void login(String name,String pwd);
    }
    
    interface ILoginView<ILoginPresenter>{
        void loginok();
        void loginErro();
    }
    

    }

    3.建立presenter的实现类

    public class LoginPresenter implements     ILoginContract.ILoginPresenter {
    ILoginContract.ILoginView view;
    
    
    public LoginPresenter(ILoginContract.ILoginView view) {
        this.view = view;
    }
    
    @Override
    public void login(String name, String pwd) {
    
    }
    }
    

    我们按常规的方式会把LoginPresenter 在activity中声明成员变量,并new 出来如下:

     public class LoginActivity extends AppCompatActivity  implements ILoginContract.ILoginView{
        
       LoginPresenter  presenter;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
           presenter = new LoginPresenter(this);//这里有问题
        }
    
        @Override
        public void loginok() {
    
        }
    
        @Override
        public void loginErro() {
    
        }
    }
    

    如上,这里的presenter是new出来的,达到互相依赖的关系,这样就把彼此仅仅的耦合在一起了,一旦presenter的构造方法改变就要同时改变activity中的代码,这不是我们想要的。
    那么dagger2 是如何注入的呢;
    首先我们需要新建两个类文件:
    Moudule类

    @Module
    public class LoginMoudule {
    private final ILoginContract.ILoginView view;
    public LoginMoudule(ILoginContract.ILoginView view) {
        this.view = view;
    }
    @Provides
    ILoginContract.ILoginView provideLoginView(){
        return view;
    }
    }
    

    Component类

    @Component(modules = LoginMoudule.class)
    public interface LoginComponent {
     void inject(LoginActivity activity);
    }
    

    可见moudule类用@Module 注解,构造方法中注入view层, 并用@Provides注解一个返回ILoginView的方法;Component类用@Component(modules = LoginMoudule.class)注解可见Component与LoginMoudule.class必然存在某种关系,并inject方法把activity联系起来,这样这几个类就肯定通过某种方法联系起来了,但这些联系并不需要我们程序员去写什么了。

    接下来就是对view和presenter两个类内部进行改造:activity

    public class LoginActivity extends AppCompatActivity  implements ILoginContract.ILoginView{
        @Inject//这里加注解
        LoginPresenter presenter;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
        }
    
        @Override
        public void loginok() {
    
        }
    
        @Override
        public void loginErro() {
    
        }
    }
    

    presenter类

    public class LoginPresenter implements ILoginContract.ILoginPresenter {
    ILoginContract.ILoginView view;
    
    @Inject//这里注解
    public LoginPresenter(ILoginContract.ILoginView view) {
        this.view = view;
    }
    
    @Override
    public void login(String name, String pwd) {
    }
    }
    

    在activity中的依赖的presenter添加@Inject注解,同时在presenter中的构造方法同时加这个@Inject的注解,之后build一下整个项目,在项目的project视图下的build的文件夹下生成了如下的几个类,这就是dagger2 通过apt生成的辅助类,也是dagger2的玄机所在。

    Paste_Image.png

    回到activity中:

    public class LoginActivity extends AppCompatActivity  implements ILoginContract.ILoginView{
        @Inject
        ILoginContract.ILoginPresenter presenter;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
    //添加此句
            DaggerLoginComponent.builder().loginMoudule(new LoginMoudule(this)).build().inject(this);
        }
    
        @Override
        public void loginok() {
    
        }
    
        @Override
        public void loginErro() {
    
        }
    }
    

    dagger2生成的义Dagger前缀的Component内部完成了这一系列注入过程。
    到此为止mvp中v和p的互相注入通过dagger2已经完成,此时可以测试一下,看presenter是否会报空指针。你可能会说了,wtf(what the fuck)这么麻烦!!呵呵,和我一开始一样的。但是想想框架不一定就是能满足程序员的懒,框架麻烦但是能让我们的程序更健壮,或者维护起来会省很多事啊!想你说的 ,懒!没办法。
    好今天就到这里,接下来会详细介绍dagger2 的细节,每天学一点点,厚积薄发。

    每天发的东西都是我正在学习的东西,学习的同时,与更多人分享,一能增进我的记忆,同时提出自己的见解与大家互相促进提高,同时也希望收到拍砖

    相关文章

      网友评论

        本文标题:dagger2 循序渐进学习(包会)(二)

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