dagger2使用入门详解(一)

对于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 api
apt '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使用入门详解(一)_第1张图片

由于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的入门使用:

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

dagger2使用入门详解(一)_第2张图片


如上图,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来提供,代码分别如下:

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


@Module
public 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);
    }
}

@Module
public 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文件夹下,自动生成相应的代码,生成代码目录如下:

dagger2使用入门详解(一)_第3张图片

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

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

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

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





你可能感兴趣的:(新技术)