对于Dagger2,我有句话要说

题外话

    最近接手了一个很奇葩的项目,怎么奇葩呢?Java中混杂着kotlin,kotlin中带着MVP,MVP中混着Dagger2,还有什么RxJava,Retrofit等目前Andorid开发的标配。由于对kotlin只是停留在小打小闹上,充其量也就是基本了解kotlin语法,真要用它写项目,本宝宝内心其实是拒绝的;这还不算事,关键是对Dagger2也是一无所知,以前不是不想学这个Dagger2,原因有很多,第一是每次写个component,都需要重写编译一次,才能获取DaggerComponent,自己的电脑比较渣,经常搞几次就烦了就没再坚持下去弄了;第二我在刚开始看Dagger2时,思想还没有达到现在的高度,不知道解耦,不知道面向对象六大原则,只知道我需要哪些东西,直接new一个就可以了,简单直接高效。现在项目里面有了,那就需要真正去学一下了,哎,电脑渣也要学啊。


简单说明

    当然了,我也是现学现卖,在这里我也不打算扯一些理论和概念,也不想扯Dagger2的历史与发展,更不想扯Dagger2里面的注解到底什么意思,这些东西网上遍地都是,而且即使你去读了,也感觉云里雾里的。不骗你,我也是这么来的,在这篇文章之前,我也是读了n篇文章,发现还是很多东西不懂,只好总结一下别人博客里面的dome,然后自己去理解。如果你和我一样有这种感觉,那么不妨先不要去理解概念,先看看我写的这些例子吧。


环境搭建

    这个我个人感觉还是蛮容易,但是由于网上很多都是旧版本的教程,都是需要什么apt+compile+dagger2,由于我这是最近几天写的,就查了一下Dagger2的官方配置,只需要build.grade下配置


dependencies {
    ...
    compile 'com.google.dagger:dagger:2.9'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.9'
}

实例一 (UserInfo对象)

     对于Dagger2的理解,我先给出自己的观点,它就是把当初我们new 对象的地方 给搞到某个地方统一管理了,这个管理的地方可能有点绕,我们先不说,那么看看使用Dagger2初始化对象是怎么个弄法吧。

1.定义Bean对象

    先定义一个UserInfo对象,这个基本上都知道了,我就不多扯了:

public class UserInfo{

    public String name ;
    public int age ;


    public UserInfo() {

    }

}

2.建立Module

    也就是创建一个java文件,命名可以自己随便取,但是为了专业和大佬们的一致性,还是建议文件名后面加上Module,然后需要注意一下,有两个注解@Provides和@Module,这个就先不解释了,你先抄一遍再说。比如下面我写的SimpleModule:注意这两个注解一个都不能少,少了就尴尬了。 其实你也看到了,这里new了一个UserInfo(),我猜八成就是以前我们撸的new 对象的方法就被移到这里啦。


@Module
public class SimpleModule {

    @Provides
    public UserInfo getUserInfo() {
        UserInfo info = new UserInfo();
        info.age = 18 ;
        info.name = "tom";
        return info;
    }

}
3.建立Component

     这是一个接口,但是也需要注意一个注解@Component,和关联的module,不说了,你先按照这方面写吧,赶紧上车;这里的modules就是上面第2步定义的Module,这个SimpleActivity就是你将要使用的Activity,或者你写个MainActivity也行,记住一定要写目标Activity,不要写个BaseActivity或者AppCompatActivity,至于原因是什么,看完这套东西,估计你就知道了。

@Component(modules = SimpleModule.class)
public interface SimpleComponent {

    void inject(SimpleActivity activity) ;
}
4.编译获取DaggerXXXComponent

    android studio直接Ctrl+F9就可以了,只要gradle没报什么错误,就可以进行第5步了,如果出现了某种错误,先看看第一到三步配置好了没有,还有错误,请google之。

5. Activity中使用

    没有错误了,那么我们的Activity就可以这么写了:

public class SimpleActivity extends AppCompatActivity {

    @Inject
    UserInfo userInfo;

    TextView mTv ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTv = (TextView) findViewById(R.id.id_tv);

        DaggerSimpleComponent.builder().simpleModule(new SimpleModule()).build().inject(this);
    }

    public void getInfo(View view) {
        mTv.setText(userInfo.name + "---->>" + userInfo.age);
    }
}

需要注意的几点是:第一UserInfo上头有个注解@Inject,这个一定要写,不然的话UserInfo就真没地方初始化了。第二就是

DaggerSimpleComponent.builder().simpleModule(new SimpleModule()).build().inject(this);

这句话可以理解为我给userInfo初始化了。现在我们点击一下按钮,看看我们的userInfo是不是报NullPointerException了:
这里写图片描述

好了, 你看到了这个UserInfo在没有被new的情况下,还是被初始化了,这就是Dagger2所做的动作,基本上这个小例子就阐述了Dagger2的功能。好了,你到现在Dagger2已经学会,可以出去装13了,那么今天的扯淡也就好了。

哪有这么简单的事啊?? 你看看下面这个你会不会??

实例二(使用Dagger2实现ViewPager)

    实现如下:
这里写图片描述
由于这次还是个例子,那么这次就反过来看吧,先看Activity中是怎么写的:


public class Simple2Activity extends AppCompatActivity {

    ViewPager mViewPager;

    @Inject
    CustomPagerAdapter mCustomPagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple2);

        mViewPager = (ViewPager) findViewById(R.id.id_view_pager);

        DaggerSimple2Component.builder().commonModule(new CommonModule(this)).build().inject(this);
    }

    public void addNewTextView(View view) {
        mViewPager.setAdapter(mCustomPagerAdapter);
    }
}

同样,我们看到了CustomPagerAdapter 被@Inject注解所修饰,而且还出现了DaggerSimple2Component这个Component,按照道理,先去看看CustomPagerAdapter,看看与我们平时写的Adapter是否有不同?

public class CustomPagerAdapter extends PagerAdapter {

    private Context context;
    private List<String> list;

    @Inject
    public CustomPagerAdapter(Context context, List<String> list) {
        this.context = context;
        this.list = list;
        Log.d("pagerAdapter","it has been initialized") ;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ImageView iv = new ImageView(context);
        iv.setScaleType(ImageView.ScaleType.CENTER_CROP);

        Glide.with(context).load(list.get(position)).into(iv);

        container.addView(iv);
        return iv;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }
}

98%的地方都是相同的?那还有2%是哪里不同呢? 你看,CustomPagerAdapter的构造函数上也被修饰了@Inject注解。这个先记住,不然又要扯概念,扯理论然后看源码画图,估计没半小时是不明白怎么回事的。看完了CustomPagerAdapter,再去看DaggerSimple2Component这个类,去掉前缀Dagger,那么就去看Simple2Component了:

@Component(modules = CommonModule.class)
public interface Simple2Component {

    void inject(Simple2Activity activity);

}

这里基本上 没什么收获,那就看看CommonModule里面的东西吧:


@Module
public class CommonModule {

    private Context mContext;

    public CommonModule(Context context) {
        this.mContext = context;
    }

    @Provides
    public Context getContext(){
        return mContext;
    }

    @Provides
    public List<String> getList() {
        List<String> mList = new ArrayList<>();
        mList.add("http://pic40.nipic.com/20140424/10558908_213423765000_2.jpg");
        mList.add("http://pic35.photophoto.cn/20150529/0014026744554538_b.jpg");
        mList.add("http://pic24.nipic.com/20121018/7184338_161023557132_2.jpg");
        mList.add("http://pic14.nipic.com/20110427/5006708_200927797000_2.jpg");

        return mList;

    }

}

在这个CommonModule中,我们发现了很多奇怪的东西,被注解Provides修饰的两个方法,其返回值分别为Context对象和List对象,而这两个对象我们好像哪里需要用得到呢? 对了,那个CustomPagerAdapter中用到了:

    @Inject
    public CustomPagerAdapter(Context context, List<String> list) {
        this.context = context;
        this.list = list;
        Log.d("pagerAdapter","it has been initialized") ;
    }

看到这里,我想即使你不明白Dagger2内部是怎么玩了,但是我们脑子中好像有个印象,其实所有的地方,该new对象的地方都new了对象,只不过Dagger2中很隐秘或者说很恶心,都在拐弯抹角的去new我们需要的对象。这里也不例外,当CustomPagerAdapter需要两个参数Context和List时,有些地方其实已经给我们提供了。对于其内部怎么变换,现在扯出来还有些过早,因为还有些用法没有说出来,过早的扯出来 我们很多东西都会模棱两可,等我把这东西的用法说完了,然后再去看看源码怎么写的吧。

结尾

    基本用法我就说到这里吧,鉴于时间关系,下次再说一下进一步的用法吧。个人感觉Dagger2并不是很难,至少你在看了它的源码之后,但是难点在哪里呢?我个人感觉,就是很多人一上来就要问Module,Component,Scope到底什么意思,其实这些问题等你先会写Dagger2之后,再去弄懂也不迟的,而且更有效果。另外看了很多的博客,有很多错误的地方(比如scope作用域)都是没有好好研究源码,而道听途说得到了,对此我也被坑了很多次,对此,还是那句话MMP吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值