Kotlin+Dagger2+MVP框架搭建(一)
文章目录
一、项目配置
app:build.gradle文件中
apply plugin: 'kotlin-kapt'
android {
、、、
}
dependencies {
、、、
//dagger2依赖添加
implementation 'com.google.dagger:dagger:2.21'
//(注意Dagger官网使用的是annotationProcessor,可能出现各种问题,建议使用Kapt)
kapt 'com.google.dagger:dagger-compiler:2.21'
}
二、简单使用Dagger
1.新建接口声明MainActivity的View接口(MVP中的V)和Presenter接口(MVP中的P)
interface MainControl {
interface View {
fun setData(user: User)
}
interface Presenter {
fun setData()
}
}
2.新建一个数据类模拟Model中提供的数据
data class User(val name: String,val id: Int)
3.新建Model
注:可以理解为是一个内容提供者类,需要@Module标签修饰类,提供内容的方法前需要@Provides标签修饰
@Module
class MainModel(private val view: MainControl.View) {
@Provides
fun providerView(): MainControl.View {
return view
}
@Provides
fun providerUser(): User {
return User("张三", 100)
}
}
4.新建Component
注:这是一个必要的接口,可以理解为容器,用于包容Model产生的东西,需要使用@Component(…)标签修饰接口,用于指定包含的Model。其中modules的值是指向直接包含的Model文件集合,dependencies的值指向所依赖的附属Component文件集合,dependencies后面叙说,这里暂时只用modules
@Component(modules = arrayOf(MainModel::class))
interface MainComponent {
fun inject(activity: MainActivity)
}
5.新建Presenter
需要实现 MainControl.Presenter 接口,并使用@Inject标签修饰构造函数,表明需要注入的参数
class MainPresenter @Inject
constructor(private val view: MainControl.View,private val user: User) : MainControl.Presenter {
override fun setData() {
view.setData(user)
}
}
6.在Activity中实现MainControl.View接口,并“Build->Make Project”(或者Ctrl+F9)构建一下项目,使之自动生成Dagger所需文件。然后添加如下代码:
class MainActivity : AppCompatActivity(), MainControl.View {
//用于注入Presenter对象
@Inject
lateinit var presenter: MainPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Build之后添加,用于初始化,并生成Model中两个方法提供的对象
DaggerMainComponent.builder().mainModel(MainModel(this))
.build()
.inject(this)
presenter.setData()
}
override fun setData(user: User) {
Toast.makeText(this,user.name,Toast.LENGTH_SHORT).show()
}
}
三、依赖组件Component
1.新建Model,并注释掉MainModel类中providerUser()方法
注:因为Model中不能直接提供两个返回类型相同的对象,所以这里为了方便观察Component的依赖将MainModel中的providerUser()方法注释掉
@Module
class UserModel() {
@Provides
fun providerUser(): User {
return User("李四", 200)
}
}
@Module
class MainModel(private val view: MainControl.View) {
@Provides
fun providerView(): MainControl.View {
return view
}
}
2.新建Component
@Component(modules = arrayOf(UserModel::class))
interface UserComponent {
fun getData() : User
}
3.修改MainComponent
@Component(modules = arrayOf(MainModel::class),dependencies = arrayOf(UserComponent::class))
interface MainComponent {
fun inject(activity: MainActivity)
}
4.“Build->Make Project”(或者Ctrl+F9)构建一下项目,并将MainActivity做如下修改:
class MainActivity : AppCompatActivity(), MainControl.View {
@Inject
lateinit var presenter: MainPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//修改,用于依赖UserComponent
DaggerMainComponent.builder().mainModel(MainModel(this))
.userComponent(DaggerUserComponent.builder().userModel(UserModel()).build())
.build()
.inject(this)
presenter.setData()
}
override fun setData(user: User) {
Toast.makeText(this,user.name,Toast.LENGTH_SHORT).show()
}
}
四、 @Qualifier 和 @Named标签使用
这两个标签用于区分Model中存在被 @Provides标签修饰的返回对象类型相同的方法
注:以下代码基于第二步时的代码修改
注:因Kotlin中变量编译为 Java 字节码的时候会对应三个目标,一个是变量本身、还有 getter 和 setter,所以需要使用field标记指定@Qualifier 和 @Named标签应用到 变量上(解释来源Kotlin中国)
1、@Named标签使用
注:在@Named(“…”)中的字符串是标记常量,Dagger就是通过标记常量查找对应方法的,所以使用时前后标记需要一致
1.修改MainControl
interface MainControl {
interface View {
fun setData(user: User)
}
interface Presenter {
//修改
fun setData(user: User)
}
}
2.修改MainPresenter
class MainPresenter @Inject
constructor(private val view: MainControl.View) : MainControl.Presenter {
override fun setData(user: User) {
view.setData(user)
}
}
3.修改MainModel
@Module
class MainModel(private val view: MainControl.View) {
@Provides
fun providerView(): MainControl.View {
return view
}
@Provides
@Named("tag1")
fun providerUser(): User {
return User("张三", 100)
}
@Provides
@Named("tag2")
fun providerUser2(): User {
return User("李四", 200)
}
}
修改MainActivity
class MainActivity : AppCompatActivity(), MainControl.View {
@Inject
lateinit var presenter: MainPresenter
@Inject
@field:Named("tag1")
lateinit var user1: User
@Inject
@field:Named("tag2")
lateinit var user2: User
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMainComponent.builder().mainModel(MainModel(this))
.build()
.inject(this)
presenter.setData(user1)
presenter.setData(user2)
}
override fun setData(user: User) {
Log.e("User"," name:"+user.name+" id:"+user.id)
}
}
2、@Qualifier 标签使用
1.新建@Qualifier标签Tag1和Tag2两个文件
@Qualifier
annotation class Tag1
@Qualifier
annotation class Tag2
2.使用Tag1和Tag2替换@Named使用位置
@Module
class MainModel(private val view: MainControl.View) {
@Provides
fun providerView(): MainControl.View {
return view
}
@Provides
@Tag1
fun providerUser(): User {
return User("张三", 100)
}
@Provides
@Tag2
fun providerUser2(): User {
return User("李四", 200)
}
}
class MainActivity : AppCompatActivity(), MainControl.View {
@Inject
lateinit var presenter: MainPresenter
@Inject
@field:Tag1
lateinit var user1: User
@Inject
@field:Tag2
lateinit var user2: User
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMainComponent.builder().mainModel(MainModel(this))
.build()
.inject(this)
presenter.setData(user1)
presenter.setData(user2)
}
override fun setData(user: User) {
Log.e("User"," name:"+user.name+" id:"+user.id)
}
}
链接
Kotlin中国:https://kotlintc.com/articles/2679
Dagger2入门:https://www.jianshu.com/p/92f793e76654