最简洁的 Kotlin Mvp封装

这篇重点贴下 Kotlin Mvp 的代码,Kotlin 中 MVVM已经相当盛行了,但处理业务逻辑较多的场景中 Mvp 还是有需要的,废话不多说,直接上代码

首先定义统一的 IView 接口,定义 BaseView 中的行为,新建 BaseView.kt 文件

interface IView {

    fun showToast(msg: String)

    fun showLoading(color: Int = Color.BLUE, tip: String = " 正在加载中 ... ")

    fun hideLoading()

    fun onError(throwable: Throwable)
}

接着定义 IPresenter 接口,当然新建 BasePresenter.kt 文件最好

interface IPresenter

这时就需要将 Presenter 与 View 相关联了,首先 Presenter 中引入 View

interface IPresenter {
    val mView: View
}

接着 View 中添加 Presenter 

interface IView {
    val mPresenter: Presenter
    // ...
}   

上述的 IPresenter 会出错,因为 IPresenter 有泛型,Kotlin 是真泛型的语言,所以修改为如下

interface IView>>{
    val mPresenter: Presenter
    // ...
}

这里同样的 IView 也需要将泛型添加进去。这样一改,IPresenter 类中也需要将泛型补全了,代码如下

interface IPresenter>> {
    val mView: View
}

同样的方式补全后,我们发现两个类都出错了!!!提示 Type argument is not within its bounds。不要慌,这时了解 Kotlin 的都知道,此时协变逆变就该上场了

如果你的类是将泛型作为内部方法的返回,那么可以用 out;如果你的类是将泛型对象作为函数的参数,那么可以用 in;这里不多解释,两个类都加上 out 修饰即可。

interface IView>>
interface IPresenter>>

接口定义完成,接下来定义基类 BaseView、BasePresenter。先定义 abstract 的 BasePresenter

abstract class BasePresenter>> : IPresenter {
    override lateinit var mView: View
}

这里使用 lateinit 延迟初始化,当然编译器不能通过,提示 Type parameter View is declared as 'out' but occurs in 'invariant' position in type View。简单说就是被声明为out的类型T不能出现在输入的位置,而我们知道如何使用,所以需要 @UnsafeVariance 来修饰,意思是告诉编译器我知道,你不要管我知道怎么搞

abstract class BasePresenter>> : IPresenter {
    override lateinit var mView: @UnsafeVariance View
}

BaseView 写起来就简单多了

interface BaseView>> : IView {
}

View 和 Presenter 书写完成后,自然是封装 BaseActivity 了,我这里定义为 BaseMvpActivity,抽象类,继承自 AppCompatActivity,当然你也可以继承自其他的初始 Activity。

abstract class BaseMvpActivity>> :
    AppCompatActivity(), BaseView {
    override val mPresenter: Presenter
        get() = TODO("Not yet implemented")

    override fun showToast(msg: String) {
        TODO("Not yet implemented")
    }

    override fun showLoading(color: Int, tip: String) {
        TODO("Not yet implemented")
    }

    override fun hideLoading() {
        TODO("Not yet implemented")
    }

    override fun onError(throwable: Throwable) {
        TODO("Not yet implemented")
    }
}

将 IView 中方法都实现了,这里重点关注下 Presenter 的初始化,以及 Presenter 与 View 的关联。通常会通过抽象方法交由子类去实现,而这里用到了泛型,所以我们通过反射去初始化,调用 findPresenterClass 得到 Presenter 的类型


    private fun findPresenterClass(): Class {
        var thisClass: Class<*> = this.javaClass
        while (true) {
            (thisClass.genericSuperclass as? ParameterizedType)?.actualTypeArguments?.firstOrNull()
                ?.let {
                    return it as Class
                }
                ?: run {
                    thisClass = thisClass.superclass ?: throw IllegalArgumentException()
                }
        }
    }

自然我们在 Activity 初始化时调用,代码修改如下,同事将 View 与 Presenter 想关联

//    override val mPresenter: Presenter
//        get() = TODO("Not yet implemented")

    final override val mPresenter: Presenter

    init {
        mPresenter = findPresenterClass().newInstance()
        mPresenter.mView = this
    }

使用

如在 MainActivity 中使用,定义 MainPresenter ,MainView ,这里简单的一个 login 测试方法

class MainPresenter : BasePresenter() {
    fun login(hello: String) {
        mView.onLoginSuccess("$hello $hello")
    }

}

interface MainView : BaseView {
    fun onLoginSuccess(s: String)
}

MainActivity 代码,直接贴出来,同样如此简单

class MainActivity : BaseMvpActivity(), MainView {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val hello = findViewById(R.id.btn)
        hello.setOnClickListener {
            mPresenter.login(hello.text.toString())
        }
    }

    override fun onLoginSuccess(s: String) {
        Log.d("Mvp", s);
    }
}

这样一个最简洁的 Kotlin Mvp 就实现了

 

你可能感兴趣的:(Kotlin)