架构进阶,Dagger2的原理及使用详解

/***

  • 第一步 添加依赖关系
    */
    //第一种方式
    DaggerMainConponent.create().inject(this);

//第二种方式
DaggerMainConponent.builder().build().inject(this);

/***

  • 第三步 调用A 对象的方法
    */
    a.eat();
    }
    }

肯定有小伙伴说了,为了拿到一个对象,这么大个弯,太麻烦了。别急慢慢看,路要一步一步走嘛

3. 高级用法
(1)构造方法需要其他参数时候

怎么说呢,就和最来时的意思一样,

A a = new A(new B());
a.eat();

这种情况,如何使用Dagger2呢

肯定有小伙伴这么想

@Provides
A providerA() {
return new A(new B());
}

直接 new 一个B ,这样的使用方法,是不对的!!!!!!,不对的!!!!!!!,不对的!!!!!!!!!

正确的打开方式

这时候,我们什么都不用该,只需要在moudule中添加一个依赖就可以了

@Module
public class MainModule {

/***

  • 构造方法需要其他参数时候
  • @return
    */
    @Provides
    B providerB() {
    return new B();
    }

@Provides
A providerA(B b) {
return new A(b);
}
}

(2) 模块之间的依赖关系

模块与模块之间的联系,

@Module (includes = {BModule.class})// includes 引入)
public class AModule {
@Provides
A providerA() {
return new A();
}
}

这样的话,Dagger会现在A moudule 中寻找对象,如果没找到,会去找module B 中是否有被Inject注解的对象,如果还是没有,那么GG,抛出异常

一个Component 应用多个 module

@Component(modules = {AModule.class,BModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}

dependencies 依赖其他Component

@Component(modules = {MainModule.class}, dependencies = AppConponent.class)
public interface MainConponent {
void inject(MainActivity activity);
}

注意 这里有坑。一下会讲解

(3) @Named注解使用

相当于有个表示,虽然大家都是同一个对象,但是实例化对象不同就不如

A a1 = new A();
A a2 = new A();

// a1 a2 能一样嘛

Module中 使用@Named注解

@Module
public class MainModule {

private MainActivity activity;

public MainModule(MainActivity activity) {
this.activity = activity;
}

@Named(“dev”)
@Provides
MainApi provideMainApiDev(MainChildApi mainChildApi, String url) {
return new MainApi(mainChildApi, activity,“dev”);
}

@Named(“release”)
@Provides
MainApi provideMainApiRelease(MainChildApi mainChildApi, String url) {
return new MainApi(mainChildApi, activity,“release”);
}

}

在Activity/Fragment中使用

public class MainActivity extends AppCompatActivity {

@Named(“dev”)
@Inject
MainApi apiDev;

@Named(“release”)
@Inject
MainApi apiRelease;

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

DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.mainChildModule(new MainChildModule())
.build()
.inject(this);
apiDev.eat();
apiRelease.eat();
Log.i(“TAG”,“apiDev—>” + apiDev);
Log.i(“TAG”,“apiRelease—>” + apiRelease);
}

}

打印Log

07-14 01:46:01.170 2006-2006/? I/TAG: apiDev—>com.allen.rxjava.MainApi@477928f
07-14 01:46:01.170 2006-2006/? I/TAG: apiRelease—>com.allen.rxjava.MainApi@f2b291c

(4) @Singleton注解

单利模式,是不是超级方便,你想然哪个对象单利化,直接在他的Provider上添加@Singleton 就行了

例如

@Singleton
@Provides
A providerA(B b) {
return new A(b);
}

注意: 第一个坑!!!
如果 moudule所依赖的Comonent 中有被单利的对象,那么Conponnent也必须是单利的

@Singleton
@Component(modules = {MainModule.class})
public interface MainConponent {
}

然后 在Activity中使用,直接打印a1 a2 的地址,

@Inject
A a2;
@Inject
A a1;

可以看到Log

12-30 01:32:58.420 3987-3987/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba
12-30 01:32:58.420 3987-3987/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba

不相信的小伙伴可以吧@Singleton去掉试试

现在我们完成了单利,然后做了一个事情,就是点击某个按钮,跳转到一个新的Activiry,两边都引用同样一个A 对象,打印A 的地址,

说一下,一个Conponent 可以被对个Activity/Fragment 引用,如

@Singleton
@Component(modules = {MainModule.class})
public interface MainConponent {
void inject(MainActivity activity);
void inject(TestAct activity);
}

上面与两个Activity, MainActivity 和 TestAct ,都引用相同的 对象,答应地址看看

12-30 00:48:17.477 2788-2788/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba
12-30 00:48:17.517 2788-2788/com.allens.daggerdemo E/TAG: A2---->com.allens.daggerdemo.Bean.A@4f81861

竟然不同,说好的单利呢

注意: 第二个坑,单利对象只能在同一个Activity中有效。不同的Activity 持有的对象不同

那有人就要问了,没什么办法么,我就想全局只要一个实例化对象啊? 办法肯定是有的,

(5) 自定义Scoped

/**

  • @作者 : Android架构
  • @创建日期 :2017/7/14 下午3:04
  • @方法作用:
  • 参考Singleton 的写法
  • Scope 标注是Scope
  • Documented 标记在文档
  • @Retention(RUNTIME) 运行时级别
    */
    @Scope
    @Documented
    @Retention(RUNTIME)
    public @interface ActivityScoped {
    }

首先想一下,什么样的对象,能够做到全局单例,生命周期肯定和APP 绑定嘛,这里我做演示,一个AppAip 我们要对这个对象,全局单利,所以二话不说,先给Application 来个全家桶,

Module

@Module
public class AppModule {

@Singleton
@Provides
AppApi providerAppApi() {
return new AppApi();
}
}

Component

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
AppApi getAppApi();
}

Application

public class MyApp extends Application {

private AppConponent appComponent;

@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppConpoment.create();
}

public AppConponent getAppComponent() {
return appConponent;
}
}

最后是如何使用

首先,这个是个桥梁,依赖方式,上文已经说过了

@ActivityScoped
@Component(modules = {MainModule.class}, dependencies = AppConponent.class)
public interface MainComponent {
void inject(MainActivity activity);
void inject(TestAct activity);
}

细心的小伙伴可能已经发现了,只有在上面一个MainComponent添加了一个@ActivityScoped,这里说明一下,@Singleton是Application 的单利

注意,第三个坑,子类component 依赖父类的component ,子类component的Scoped 要小于父类的Scoped,Singleton的级别是Application

所以,我们这里的@Singleton 级别大于我们自定义的@ActivityScoped,同时,对应module 所依赖的component ,也要放上相应的Scope

好吧,上面的例子,打印Log.

12-30 02:16:30.899 4717-4717/? E/TAG: A1---->com.allens.daggerdemo.Bean.AppApi@70bfc2
12-30 02:16:31.009 4717-4717/? E/TAG: A2---->com.allens.daggerdemo.Bean.AppApi@70bfc2

一样啦

爬坑指南(极度重要)

  1. Provide 如果是单例模式 对应的Compnent 也要是单例模式
  2. inject(Activity act) 不能放父类
  3. 即使使用了单利模式,在不同的Activity 对象还是不一样的
  4. 依赖component, component之间的Scoped 不能相同
  5. 子类component 依赖父类的component ,子类component的Scoped 要小于父类的Scoped,Singleton的级别是Application
  6. 多个Moudle 之间不能提供相同的对象实例
  7. Moudle 中使用了自定义的Scoped 那么对应的Compnent 使用同样的Scoped
(6)Subcomponent

这个是系统提供的一个Component,当使用Subcomponent,那么默认会依赖Component

例如

@Subcomponent(modules = TestSubModule.class)
public interface TestSubComponent {
void inject(MainActivity activity);
}
@Component(modules = {MainModule.class})
public interface MainConponent {
TestSubComponent add(TestSubModule module);
}

在TestSubComponent中 我void inject(MainActivity activity);,便是这个桥梁,我是要注入到MainActivity,但是dagger 并不会给我生成一个Dagger开头的DaggerTestSubComponent 这个类,如果我想使用TestSubModule.class里面提供的对象,依然还是使用DaggerMainConponent例如

DaggerMainConponent
.builder()
.mainModule(new MainModule())
.build()
.add(new TestSubModule())
.inject(this);

可以看到这里有一个add的方法,真是我在MainConponent添加的TestSubComponent add(TestSubModule module);

(7)lazy 和 Provider

public class Main3Activity extends AppCompatActivity {

@PresentForContext
@Inject
Lazy lazy;
@PresentForName
@Inject
Provider provider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);

AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
ActivityComponent activityComponent = DaggerActivityComponent.builder()
.appComponent(appComponent)
.activityModule(new ActivityModule())
.build();

activityComponent.injectActivity(this);
Present present = lazy.get();
Present present1 = provider.get();
}
}

其中Lazy(懒加载)的作用好比component初始化了一个present对象,然后放到一个池子里,需要的时候就get它,所以你每次get的时候拿到的对象都是同一个;并且当你第一次去get时,它才会去初始化这个实例.

procider(强制加载)的作用:

1:同上当你第一次去get时,它才会去初始化这个实例

2:后面当你去get这个实例时,是否为同一个,取决于他Module里实现的方式

最后

代码真的是重质不重量,质量高的代码,是当前代码界提倡的,当然写出高质量的代码肯定需要一个相当高的专业素养,这需要在日常的代码书写中逐渐去吸收掌握,谁不是每天都在学习呀,目的还不是为了一个,为实现某个功能写出高质量的代码。

所以,长征路还长,大家还是好好地做个务实的程序员吧。

最后,小编这里有一系列Android提升学习资料,有兴趣的小伙伴们可以来看下哦~

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

代码真的是重质不重量,质量高的代码,是当前代码界提倡的,当然写出高质量的代码肯定需要一个相当高的专业素养,这需要在日常的代码书写中逐渐去吸收掌握,谁不是每天都在学习呀,目的还不是为了一个,为实现某个功能写出高质量的代码。

所以,长征路还长,大家还是好好地做个务实的程序员吧。

最后,小编这里有一系列Android提升学习资料,有兴趣的小伙伴们可以来看下哦~

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值