Dagger2 (一)的使用

作者: zcwfeng | 来源:发表于2021-01-11 00:08 被阅读0次

IOC

IOC(Inversion of Control)
是原来由程序代码中主动获取的资源,转变由第三方获取并使原来的代码被动接收的方式,以达到解耦的效果,称为控制反转
这种注入方式,也是共享内存的一种方式。

ioc.png

基本配置

参考官网配置 github 上官网dagger
我们自己在这里用

implementation 'com.google.dagger:dagger:2.4'
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'

使用逻辑

使用逻辑.png

module:用于提供对象
component:用于组织module并进行注入

基本使用

1. 提供用于注入的对象
package top.zcwfeng.daggersample.data
class HttpObject {
}

package top.zcwfeng.daggersample.data
class DatabaseObject {
}
2. 编写Module
/**
 * 用来提供对象
 */
//@Singleton
@Module
class HttpModule {
    //@Singleton
    @Provides
    fun providerHttpObject():HttpObject{
        return HttpObject()
    }
}
3. 编写Component, Kotlin的语法表示
//@Singleton
@Component(modules = [HttpModule::class,DatabaseModule::class])
interface MyComponent {
    // 这里不能用多态,父类不行
    fun injectMainActivity(mainActivity: MainActivity2)
    fun injectSecondActivity(secondActivity:SecondActivity)
}
4. 注入到Activity
class MainActivity2 : AppCompatActivity() {

    @Inject
    lateinit var httpObject1:HttpObject
    @Inject
    lateinit var httpObject2:HttpObject
...
}
5.rebuild项目让APT生成需要的文件
6.在需要注入的类中使用

MainActivity2 补充

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        // 语法1
        DaggerMyComponent.create().injectMainActivity(this)
        DaggerMyComponent.builder().httpModule(HttpModule())
            .databaseModule(DatabaseModule())
            .build()
            .injectMainActivity(this)

        Log.e("httpObject1",httpObject1.toString())
        Log.e("httpObject2",httpObject2.toString())

    }
7. 单利使用

将之前的Component,HttpModule 的 @Singleton 注释打开,就是单利的使用
看下输出

 Log.e("httpObject1",httpObject1.toString())
Log.e("httpObject2",httpObject2.toString())

>>>>

2021-01-09 15:07:28.079 16769-16769/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@20e7e14
2021-01-09 15:07:28.079 16769-16769/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@20e7e14

我们在SecondActivity中在次写同样方法,MainActivity2 跳转到SecondActivity

class SecondActivity : AppCompatActivity() {
    @Inject
    lateinit var httpObject:HttpObject
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        // 语法1
        DaggerMyComponent.create().injectSecondActivity(this)
        DaggerMyComponent.builder().httpModule(HttpModule())
            .databaseModule(DatabaseModule())
            .build()
            .injectSecondActivity(this)

        Log.e("httpObject",httpObject.toString() + "--sec")
    }
}

输出

2021-01-09 22:54:35.087 17385-17385/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@f024075
2021-01-09 22:54:35.087 17385-17385/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@f024075
2021-01-09 22:55:10.804 17385-17385/top.zcwfeng.daggersample E/httpObject: top.zcwfeng.daggersample.data.HttpObject@ca20d--sec

注意:以上单例只能在注入类中局部有效

为什么会一致量httpObject1和httpObject2,我们查看

DaggerMyComponent.builder().httpModule(HttpModule())
            .databaseModule(DatabaseModule())
            .build()
            .injectMainActivity(this)

build 源码
build()->DaggerMyComponent#initialize--->DoubleCheck#provider

我们看到DoubleCheck 实现了Provider的接口get(),

 @Override
  public T get() {
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          instance = result = provider.get();
          /* Null out the reference to the provider. We are never going to need it again, so we
           * can make it eligible for GC. */
          provider = null;
        }
      }
    }
    return (T) result;
  }

调到SecondActivity 后provider不是一个对象,所以单例对象不是一个是一个新对象。

全局单例

class DaggerApp: Application() {
    //lateinit var appComponent:AppComponent
    lateinit var myComponent:MyComponent
    override fun onCreate() {
        super.onCreate()
        //appComponent = DaggerAppComponent.create()
        myComponent = DaggerMyComponent.builder()
            .httpModule(HttpModule())
            .databaseModule(DatabaseModule())
            .build()
    }

}

MainActivity2 中 注入就可以

// 全局singleton
        (application as DaggerApp).myComponent.injectMainActivity(this)

SecondActivity 中同样直接注入

        (application as DaggerApp).myComponent.injectSecondActivity(this)

输出

2021-01-10 16:09:55.916 20488-20488/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@f024075
2021-01-10 16:09:55.917 20488-20488/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@f024075
2021-01-10 16:10:28.741 20488-20488/top.zcwfeng.daggersample E/httpObject: top.zcwfeng.daggersample.data.HttpObject@f024075--sec

所以全局单例,我们可以放Application中进行build,全局使用

8. 多个COMPONENT组合依赖

dagger2不能使用多个Component同时注入同一个类中
这种情况需要进行Component的组合

举个例子,我们再写一个注入实例还是注入到MainActivity2:

package top.zcwfeng.daggersample.dagger.demo2.di
class Presenter {
}
------
package top.zcwfeng.daggersample.dagger.demo2.di

import dagger.Module
import dagger.Provides
@Module
class PresenterModule {

    @Provides
    fun providePresenter():Presenter{
        return Presenter()
    }

---------
package top.zcwfeng.daggersample.dagger.demo2.di

import dagger.Component
import top.zcwfeng.daggersample.MainActivity2

@Component(modules = [PresenterModule::class])
open interface PresenterComponent {

    fun inject(mainActivity: MainActivity2)
}
》》》》编译后报错
错误: top.zcwfeng.daggersample.data.HttpObject cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
    public abstract void inject(@org.jetbrains.annotations.NotNull()
                         ^
      top.zcwfeng.daggersample.data.HttpObject is injected at
          top.zcwfeng.daggersample.MainActivity2.httpObject1
      top.zcwfeng.daggersample.MainActivity2 is injected at
          top.zcwfeng.daggersample.dagger.demo2.di.PresenterComponent.inject(mainActivity)[WARN] Incremental annotation processing requested, but support is disabled because the following processors are not incremental: dagger.internal.codegen.ComponentProcessor (NON_INCREMENTAL).

这个时候我们需要更换能听多个Component同时注入到一个类。

PresenterComponent 这个时候需要修改成下面:

@Component(modules = [PresenterModule::class])
open interface PresenterComponent {
    // 之前如果有注入过Component进入MainActivity2 同时多个会报错
    // 需要更改写法
//    fun inject(mainActivity: MainActivity2)
    fun providerPresenter():Presenter;
}

在 MyComponent中添加depencies 进行组合

@Singleton
@Component(modules = [HttpModule::class,DatabaseModule::class]
,dependencies = [PresenterComponent::class])
interface MyComponent {
    // 这里不能用多态,父类不行
    fun injectMainActivity(mainActivity: MainActivity2)
    fun injectSecondActivity(secondActivity:SecondActivity)
}

在使用的时候,看下我们DaggerApp中的onCreate

override fun onCreate() {
        super.onCreate()
        appComponent = DaggerAppComponent.create()
        myComponent = DaggerMyComponent.builder()
            .httpModule(HttpModule())
            .databaseModule(DatabaseModule())
            .presenterComponent(DaggerPresenterComponent.create())
            .build()
    }

在MainActivity2 注入表示层

....
@Inject
 lateinit var presenter: Presenter
....
//验证打印
 Log.e("presenter", presenter.toString())
....

去掉所有的@Singleton 运行验证

2021-01-10 17:47:11.266 21989-21989/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@317480a
2021-01-10 17:47:11.266 21989-21989/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 17:47:11.266 21989-21989/top.zcwfeng.daggersample E/presenter: top.zcwfeng.daggersample.dagger.demo2.di.Presenter@412a698

把之前的@Singleton 加回来再次运行看一下


2021-01-10 18:01:00.511 22378-22378/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 18:01:00.511 22378-22378/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 18:01:00.511 22378-22378/top.zcwfeng.daggersample E/presenter: top.zcwfeng.daggersample.dagger.demo2.di.Presenter@412a698

如果这个时候想要新家入得PresenterComponent 想要使用单例,那么加入@Signeton标记就会报错,如何解决,我们只能采用自定义方式。

自定义Scope

@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class UserScope{
}

@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class AppScope{
}

MyComponent 相关的我们,加上@AppScope,PresenterComponent 相关我们加上@UserScope。
输出配置

MainActivity2----->

    @Inject
    lateinit var httpObject1: HttpObject

    @Inject
    lateinit var httpObject2: HttpObject

    @Inject
    lateinit var presenter: Presenter
    @Inject
    lateinit var presenter2: Presenter
。。。

    Log.e("httpObject1", httpObject1.toString())
        Log.e("httpObject2", httpObject2.toString())
        Log.e("presenter", presenter.toString())
        Log.e("presenter", presenter.toString())

》》》输出结果
2021-01-10 18:29:15.578 22743-22743/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 18:29:15.578 22743-22743/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 18:29:15.578 22743-22743/top.zcwfeng.daggersample E/presenter: top.zcwfeng.daggersample.dagger.demo2.di.Presenter@412a698
2021-01-10 18:29:15.578 22743-22743/top.zcwfeng.daggersample E/presenter: top.zcwfeng.daggersample.dagger.demo2.di.Presenter@412a698

总结一下思路:

1》dependencies用法

  • 1.为每个Component定义自己的Scope
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class UserScope{
}

@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class AppScope{
}
    1. 进行依赖
@AppScope
@Component(modules = {HttpModule.class, DatabaseModule.class}
                ,dependencies = {PresenterComponent.class})
public interface MyComponent {
    //不能用多态
    void injectMainActivity(MainActivity mainActivity);
    void injectSecActivity(SecActivity secActivity);
}
    1. 初始化使用
DaggerMyComponent.builder()
                .httpModule(new HttpModule())
                .databaseModule(new DatabaseModule())
                .presenterComponent(DaggerPresenterComponent.create())
                .build();
  • dependencies注意事项
 scope&dependencies的使用
 1.多个component上面的scope不能相同
 2.没有scope的组件不能去依赖有scope的组件

2》@Subcomponent用法

  • subcomponet
@Subcomponent(modules = {TestSubModule.class})
public interface TestSubComponent {
    void injectMainActivity(MainActivity activity);
}
  • Component
@Component(modules = {MainModule.class})
public interface MainComponent {
    TestSubComponent getTestSubComponent();
}
  • 使用
DaggerMainComponent.create()
              .getTestSubComponent()
              .injectMainActivity(this);

这种用法不是很灵活

9. 其他用法

1》带参数module

@Module
public class MainModule {

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

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

module 中

module中:
@Named("key1")
@Provides
public User provideUser(){
    return new User("David","123");
}
@Named("key2")
@Provides
public User provideUser2(){
    return new User("David","456");

2》@Named使用

注入点:
@Named("key1")
@Inject
User user1;
@Named("key2")
@Inject 
User user2;

通过以上语法,就可以实现两个不同的key注入不一样的同类型对象

3》lazy 和 Provider

这种方式是在get的时候,才初始化需要注入的对象

声明

@Inject
    Lazy<A> lazy;
    @Inject
    Provider<A> provider;

测试

Log.i(TAG,lazy.get().hashCode()+"");
Log.i(TAG,provider.get().hashCode()+"");

相关文章

网友评论

    本文标题:Dagger2 (一)的使用

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