dagger2使用入门详解(一)

来源:互联网 发布:linux 防火墙 编辑:程序博客网 时间:2024/06/05 20:27

对于dagger2使用的好处,这里就不过多介绍,可以参考其官方文档说明点击打开链接,这里主要是讲解一下,本人在学习、使用dagger2时的一些总结,对dagger2的快速入门做一些笔记。接下来会分几篇文章来介绍一下自己对dagger2的快速入门,这一篇主要讲一下,dagger2环境的快速搭建,以及dagger2的三个重要组成部分。

一、dagger2环境的快速搭建

1.在项目的build.gradle 的添加下面的代码:

dependencies {    classpath 'com.android.tools.build:gradle:2.2.2'    //其他    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'  //添加android apt命令工具}

2.在Module的build.gradle顶部添加下面代码:

// 应用插件apply plugin: 'com.neenbedankt.android-apt'

同时在其dependencies{ }中加入以下代码同步即可:

compile 'com.google.dagger:dagger:2.0.2'             //dagger2 apiapt 'com.google.dagger:dagger-compiler:2.0.2'        //dagger2 注解处理器provided 'org.glassfish:javax.annotation:10.0-b28'   //添加android缺失的部分javax注解

注意在与butterknife一起使用时,在module的build.gradle 的dependencies{ } 里面要添加如下代码:

//butterknife注入compile 'com.jakewharton:butterknife:8.5.1'apt 'com.jakewharton:butterknife-compiler:8.5.1'//注意是apt 而不是annotationProcessor

原因的话可以点此查看详细说明 点击打开链接 。

二、dagger2的三个重要组成部分

dagger2三个重要组成部分为:module,component, container,三者的关系如下图所示:

由于dagger2主要是编译期对注解内容进行获取,所以这三个组成部分也有相应的注解符号,下面主要说明一下所涉及的注释符号:

Container:

@Inject : 通过在需要依赖注入的地方(一般为activity或fragment)使用,它能告诉dagger2这个类或字段需要依赖注入,dagger2就会构造这个类和对象的实例来满足依赖注入。

Module :  

@Module  : 用该注解修饰的类,里面主要提供该依赖对象的实例化方法,方法名一般为provide + 对象名,如provideRegister() ,同时用@Provides注解修饰。用该注解修饰这个类,当dagger2在构造类的实例时,就知道从哪里去找到相应的依赖。

@Provides : 用这个来修饰@Module注解类中的方法,表明要提供的实例化对象

Component:

@Componet : 它修饰的是一个接口,其实就是一个依赖注入器,里面提供了依赖注入的方法,方法名一般为inject(目标类对象) 。可以说它是连接@Inject 和 @Module 的中间桥梁,连接两个部分。它后面可以跟多个Module,来实例化多个对象。

当Module 、Component 准备好,在需要依赖注入的目标类中除了要@Inject 相应的对象,还需要进行一项初始化操作将依赖注入到相应的目标类中,在这操作之前一般需要rebuild一下。这样整个依赖注入过程才算完成了。。。

三、简单使用代码示例

本文将以典型的用户登录案例,将MVP架构与Dagger2结合起来!熟悉其使用场景,在场景中了解dagger2的入门使用:

先看一下这个登录案例工程的目录结构:



如上图,component,module是项目中所用到的dagger2的依赖注入器和module , bean 是mvp中的model,presenter是项目所用到的presenter层,以及p层与v层交互的接口等。

下面说一下,如何将mvp与dagger2融合到用户登录场景中,主要分为三个步骤:

1.搭建mvp架构;2.利用dagger2解耦,将m层注入p层,p层注入v层;3.rebuid项目,初始化依赖注入

(一)搭建mvp架构

M: 创建用户登录信息实体类User,这个没什么好说的,包括用户名和密码。

业务逻辑类:定义接口IUser,里面包含一个登录方法,创建一个实现类IUserImp来实现这个接口,同时定义一个接口回调OnLoginListener,监听登录成功或失败。主要看一下实现类IUserImp的代码:

public class IUserImp implements IUser{    private User mUser;    //构造传入User对象    public IUserImp(User user) {        mUser = user;    }    @Override    public void login(final String name, final String password, final OnLoginListener listener) {        Log.e("zxh", "login:mUser== " + mUser);        //模拟登录,子线程休眠一下        new Thread(new Runnable() {            @Override            public void run() {                //延时一下                SystemClock.sleep(2000);                if ("zxh".equals(name) && "123".equals(password)) {                    mUser.setName(name);                    mUser.setPassWord(password);                    listener.loginSuccess(mUser);       //成功回调                }else {                    listener.loginFailed();             //失败回调                }            }        }).start();    }}

确定P层与V层交互的接口类:IUserLoginView,里面定义与页面交互的各种逻辑:代码如下

public interface IUserLoginView {    //获取用户名和密码    String getUserName();    String getUserPassWord();    //显示和隐藏进度条    void showProgress();    void hideProgress();    //成功跳转到新页面,失败弹土司    void toMainActivity(User user);    void showFailedToast();}

接下来看一下LoginPresenter,通过持有IUserLoginView和IUserImp的引用来实现页面逻辑与业务逻辑的操作,它只有一个登录的方法,代码如下:

public class LoginPresenter {    private IUserLoginView mIUserLoginView;     //页面逻辑操作接口    private Handler mHandler;    private IUserImp mIUserImp;                 //model业务操作实现类    //通过构造传入相应的引用    public LoginPresenter(IUserLoginView IUserLoginView,Handler handler,IUserImp iUserImp) {        mIUserLoginView = IUserLoginView;        mHandler = handler;        mIUserImp = iUserImp;    }    //定义一个登录的方法    public void login(){        //显示progress        mIUserLoginView.showProgress();        Log.e("zxh","mIUserImp=="+ mIUserImp);        //开始登录        mIUserImp.login(mIUserLoginView.getUserName(), mIUserLoginView.getUserPassWord(), new OnLoginListener() {            @Override            public void loginSuccess(final User user) {                //主线程中去更新UI                mHandler.post(new Runnable() {                    @Override                    public void run() {                        mIUserLoginView.toMainActivity(user);   //进入新页面                        mIUserLoginView.hideProgress();         //隐藏progress                    }                });            }            @Override            public void loginFailed() {                //主线程中去更新UI                mHandler.post(new Runnable() {                    @Override                    public void run() {                        mIUserLoginView.showFailedToast();  //弹土司                        mIUserLoginView.hideProgress();     //隐藏progress                    }                });            }        });    }}

最后来看一下LoginActivity, 它只要持有LoginPresenter的引用,由它来完成model 与view的交互即可,代码如下:

public class LoginActivity extends AppCompatActivity implements IUserLoginView{        @Inject    LoginPresenter mLoginPresenter;     //注入引用对象    @BindView(et_name)    EditText    mEtName;    @BindView(R.id.et_password)    EditText    mEtPassword;    @BindView(R.id.btn_login)    Button      mBtnLogin;    @BindView(R.id.pb)    ProgressBar mPb;    private Unbinder mBind;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_login);        //ButterKnife绑定        mBind = ButterKnife.bind(this);        /**dagger2依赖注入初始化*/        DaggerLoginComponent.builder()                            .userModule(new UserModule())                            .iUserImpModule(new IUserImpModule())                            .loginModule(new LoginModule(this))                            .build()                            .injectLoginActivity(this);    }    @OnClick(R.id.btn_login)    public void onViewClicked() {        //点击登录按钮,执行登录逻辑        mLoginPresenter.login();    }    @Override    protected void onDestroy() {        super.onDestroy();        //解除butterknife绑定        mBind.unbind();    }    @Override    public String getUserName() {           //获取用户名        return mEtName.getText()                      .toString();    }    @Override    public String getUserPassWord() {       //获取密码        return mEtPassword.getText()                          .toString();    }    @Override    public void showProgress() {            //显示progress        mPb.setVisibility(View.VISIBLE);    }    @Override    public void hideProgress() {            //隐藏progress        mPb.setVisibility(View.GONE);    }    @Override    public void toMainActivity(User user) { //跳转到登录成功页面        Intent intent = new Intent(this,MainActivity.class);        intent.putExtra("name",user.getName());        intent.putExtra("passWord",user.getPassWord());        startActivity(intent);//        finish();    }    @Override    public void showFailedToast() {         //弹土司        Toast.makeText(this,"登录失败,用户名或密码错误...",Toast.LENGTH_SHORT).show();    }}

(二)利用dagger2解耦,将m层注入p层,p层注入v层

项目MVP框架搭好了,现在就来仔细分析一下如何利用dagger2进行依赖注入,实现项目不用new对象。

1.先来看一下LoginActivity,它里面通过@Inject 注解注入了LoginPresenter对象。假如不用dagger2,则如下所示:

//不通过dagger2则要new 好几次对象LoginPresenter presenter = new LoginPresenter(this,mHandler,new IUserImp(new User()));

要创建User对象,IUserImp对象和LoginPresenter对象。

2.接下来,看下dagger2怎么处理而不用new这些对象呢?

前文对dagger2的分析可知,通过@Module可提供这些实例化对象,那么对于这三个实例化对象,可通过三个Module来提供,代码分别如下:

@Modulepublic class UserModule {    //这里通过@Provides,提供了User实例化对象的方法,如果这边不提供provideUser()方法    //则用@Inject 对User类的构造方法注解,否则会报错,    //具体报错及原因可查看以下链接:    //http://blog.csdn.net/zxhandroid/article/details/70677260    @Provides    User provideUser() {        return new User();    }}


@Modulepublic class IUserImpModule {    //这里通过@Provides,提供了User实例化对象的方法,如果这边不提供provideIUserImp(User user)方法    //则用@Inject 对IUserImp类的构造方法注解,否则会报错,    //具体报错及原因可查看以下链接:    //http://blog.csdn.net/zxhandroid/article/details/70677260    @Provides    IUserImp provideIUserImp(User user){        return new IUserImp(user);    }}

@Modulepublic class LoginModule {    private IUserLoginView mIUserLoginView;    public LoginModule(IUserLoginView IUserLoginView) {        mIUserLoginView = IUserLoginView;    }    @Provides    IUserLoginView provideIUserLoginView() {        return mIUserLoginView;    }    @Provides    Handler provideHandler() {        return new Handler();    }    //1.带参数的方法,里面的每一个参数必须有@Provides注解的provide方法提供实例化对象或相应类中构造方法被@Inject注解,否则会报错。    //2.对于抽象类或接口,则可以通过构造方法传入,并通过provide()方法提供,如IUserLoginView。    //3.由于LoginPresenter的构造中有接口参数,所以只能通过provide方法来提供实例化对象,不能直接在其构造方法中加@Inject注解,    //原因很简单,因为抽象类或接口无法进行实例化,所以即便加上了@Inject注解在rebuild时也会报错。    @Provides    LoginPresenter provideLoginPresenter(IUserLoginView IUserLoginView, Handler handler, IUserImp iUserImp){        return new LoginPresenter(IUserLoginView,handler,iUserImp);    }}

3.创建LoginComponent 注入器提供方法注入到相应的LoginActivity中,具体见代码:

/** * Created by zengxianghui900 on 17/5/9. * 由于LoginPresenter对象实例化需要同时实例化User和IUserImp对象,因此modules要依赖这三个 */@Component(modules = {UserModule.class,IUserImpModule.class,LoginModule.class})public interface LoginComponent {        //提供方法注入到LoginActivity目标类中    void injectLoginActivity(LoginActivity loginActivity);    }

经过这些步骤就实现了依赖的注入了。

(三)rebuid项目,初始化依赖注入

接下来对整个项目进行rebuild一下,就会在项目Module 的build文件夹下,自动生成相应的代码,生成代码目录如下:


不报错,且自动生成了代码的话,就可以在LoginActivity中就可以进行初始化操作了,初始化代码如下:

/**dagger2依赖注入初始化*/DaggerLoginComponent.builder()                    .userModule(new UserModule())                    .iUserImpModule(new IUserImpModule())                    .loginModule(new LoginModule(this))                    .build()                    .injectLoginActivity(this);

到此 ,整个案例就完成了。。

代码已提交到github上,后续会不断完善,欢迎查看并star! 点击打开链接





0 0