dagger2: interface注入

134 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

image.png 上次我们简单认识了dagger2,并做了简单的使用,上次我们注入的是一个简单的类,这次我们讲解一下,如何注入一个interface。我们先来按照上次的写法来注入一个interface。

interface Person {
    fun getSex():Int
}

再写一个实现:

class Man: Person {
    override fun getSex(): Int {
        return 0
    }
}

那我们注入的时候是需要在interface上面注入还是在实现类上面注入呢?

我们现在Man上写一个注入:

class Man @Inject constructor():Person {
    override fun getSex(): Int {
        return 0
    }
}

然后在MainActivity中注入这个对象:

@Inject
lateinit var man: Man
man.getSex().let {
    Log.i("dagger2example","gender is :$it")
}

打印:

I/dagger2example: gender is :0

这样注入是可以的。那问题又来了,如果我不想用他们的子类,我想注入Person怎么办?就如这个样子:

@Inject
lateinit var person: Person

这样能注入进来吗? 看看编译:

error: Person cannot be provided without an @Provides-annotated method.
public abstract interface ExampleComponent {
                ^
      com.xxx.dagger2example.Person is injected at
          com.xxx.dagger2example.MainActivity.person
      com.xxx.dagger2example.MainActivity is injected at
          com.xxx.dagger2example.ExampleComponent.inject(com.xxx.dagger2example.MainActivity)

所以就是因为是interface,没有办法直接注入到对象里面,他需要在component里面提供一个provider方法去指明需要实现哪一个类。那我们就需要指明需要实例哪一个对象。

这里我们需要引入Dagger2的另外一个概念即Module,如果要provider一个对象,就需要在Module里面去添加,使用@Provider关键字,这个关键字只能在Module中使用,所以定义Module如下:

@Module
class ExampleModule {
    @Provides
    fun providerPerson():Person{
        return Man()
    }
}

要使成为module则必须类前面加@Module关键字。providerPerson方法的名字无所谓,只要返回的对象对应就行,但是如果有两个方法返回相同的对象那就会出错,例如:

@Module
class ExampleModule {
    @Provides
    fun providerMan():Person{
        return Man()
    }
    @Provides
    fun providerWoman():Person{
        return Woman()
    }
}

编译会报错:

Person is bound multiple times:

就会告诉你这个对象被绑定了2次。那如何我们就是有需求要返回两次的该怎么办呢?可以用起别名的方式来解决这个问题,在Module中使用:

@Module
class ExampleModule {
    @Provides
    @Named("Man")
    fun providerMan():Person{
        return Man()
    }
    @Provides
    @Named("Woman")
    fun providerWoman():Person{
        return Woman()
    }
}

用@Named关键字区分,在使用的地方:

@Inject
@Named("Woman")
lateinit var person: Person

还是使用@Named来区分到底使用哪一个对象。这样再运行:

gender is :1