前言
学习了Kotlin有一段时间了, 每次写项目/Demo的时候, 总是用到网络请求、MVP、MVVM、常用工具类、通用自定义View, 索性把这些整合到一起, 搭成一个Android的脚手架——KtArmor.
什么是KtArmor ?
KtArmor 寓意着 为Android 赋予战斗装甲, 方便开发者快速进行Android 开发。节约开发者开发时间。为了满足开发者需求, 我整合了两个分支, 分别对应着 MVP, MVVM.
- MVP分支
- 架构模式:
MVP+Kotlin - 网络请求:
Retrofit+Okhttp+Coroutine+RxJava - 功能
- 基本
BaseActivity、BaseFragment、ToolbarActivity封装 - MVP框架封装
MvpActivity、MvpFragment、BasePresenter、BaseModel封装 - 网络请求封装
BaseOkHttpClient、BaseRetrofit、RetrofitFactory - 常用控件
PlaceHolderView(占位布局),LoadingView(加载框) - 常用扩展封装(
SharedPreferences、StartActivity、Log、Toast(不重复显示))等 - MVP代码模板(
Activity、Presenter、Contract、Model)生成插件 - ....
- 基本
- 架构模式:
- MVVM分支
架构模式:MVVM+Androidx+Kotlin+LiveData+ViewModel
网络请求:Coroutines+Retrofit+Okhttp
MVP框架引入
先在 build.gradle(Project:XXXX) 的 repositories 添加:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
然后在 build.gradle(Module:app) 的 dependencies 添加:
implementation 'com.github.hyzhan43:KtArmor:mvp-1.0.4' // 根据github 引入最新版本即可
快速上手
在Application 中初始化KtArmor 框架。新建一个application 类, 如 BaseApplication, 在 BaseApplication 中, 调用KtArmor的 init 方法, 进行初始化, 参数如下:
- 第一个参数是
application, - 第二个参数是对应
RetrofitConfig配置。
class BaseApplication: Application(){
override fun onCreate() {
super.onCreate()
// 初始化KtArmor
KtArmor.init(this, MyRetrofitConfig())
}
}
再新建一个 RetrofitConfig 配置类, 继承 BaseRetrofitConfig. 并复写 baseUrl 属性, 添加自己的 baseUrl。
class MyRetrofitConfig : BaseRetrofitConfig() {
override val baseUrl: String
get() = API.BASE_URL
}
这样你就创建好了一个拥有Kotlin + Retrofit + Okhttp + Coroutine项目了。然后就可以愉快编写自己的业务代码了(●'◡'●)
Login 示例
1、LoginContract
我们先从简单登录流程来熟悉一下KtArmor。首先编写 LoginContract, 代码如下:
interface LoginContract {
interface View : BaseContract.View {
fun accountEmpty(msg: Int)
fun passwordEmpty(msg: Int)
fun loginSuc(loginRsp: LoginRsp)
}
interface Presenter : BaseContract.Presenter {
fun login(account: String, password: String)
}
}
2、LoginActivity
然后新建一个LoginActivity, 继承 MvpActivity 并传递对应 LoginContract.Presenter 泛型,实现 LoginContract.View 接口, 代码如下:
class LoginActivity : MvpActivity<LoginContract.Presenter>(), LoginContract.View {
override fun getLayoutId(): Int = R.layout.activity_login
override fun bindPresenter(): LoginContract.Presenter = LoginPresenter(this)
override fun initListener() {
super.initListener()
mBtnLogin.setOnClickListener {
mTilAccount.isErrorEnabled = false
mTilPassword.isErrorEnabled = false
// 发起登录请求
presenter.login(mEtAccount.str(), mEtPassword.str())
}
}
override fun accountEmpty(msg: Int) {
mTilAccount.isErrorEnabled = true
mTilAccount.requestFocus()
mTilAccount.error = getString(msg)
}
override fun passwordEmpty(msg: Int) {
mTilPassword.isErrorEnabled = true
mTilPassword.requestFocus()
mTilPassword.error = getString(msg)
}
override fun loginSuc(loginRsp: LoginRsp) {
toast("登陆成功!")
}
}
- bindPresenter 方法返回 LoginPresenter 实例。
- getLayoutId方法 返回LoginActivity 布局id。
这里 activity_login 里面是简单的 TextInputEditText,调用presenter, 发起登录请求。传递账号和密码。其中 str() 为 TextView 扩展方法。
str()为扩展方法
// 获取text内容
fun TextView.str(): String {
return this.text.toString()
}
3、LoginPresenter
然后我们再看看对应 LoginPresenter 实现, 继承 BasePresenter,并传递对应 LoginContract.View
class LoginPresenter(view: LoginContract.View) : BasePresenter<LoginContract.View>(view), LoginContract.Presenter {
override fun login(account: String, password: String) {
if (account.isEmpty()) {
view?.accountEmpty(R.string.account_empty)
return
}
if (password.isEmpty()) {
view?.passwordEmpty(R.string.password_empty)
return
}
launchUI({
view?.showLoading()
val response = LoginModel.login(account, password)
// 正常返回结果处理
if (response.isSuccess()) {
response.data?.let { view?.loginSuc(it) }
} else {
view?.showError(response.errorMsg)
}
}, {
// TODO 异常处理
})
}
}
在这里, 我们采用协程来实现切换线程操作。在 launchUI() 方法里面启动了一个 UI 协程,在这里调用 LoginModel 真正发起网络请求操作。
4、LoginModel
object LoginModel : BaseModel() {
suspend fun login(account: String, password: String): BaseResponse<LoginRsp> {
return launchIO { ApiManager.apiService.loginAsync(account, password).await() }
}
}
同样,LoginModel 需要继承 BaseModel(),并调用 launchIO 进行线程切换。切换到 IO线程 通过ApiManager.apiService 发起网络请求。然后调用 await() 返回结果。这里 ApiService 通过 RetrofitFactory创建, 传入 Service class。
object ApiManager {
val apiService by lazy {
RetrofitFactory.instance.create(ApiService::class.java)
}
}
interface ApiService {
@POST(API.LOGIN)
fun loginAsync(@Query("username") username: String,
@Query("password") password: String): Deferred<BaseResponse<LoginRsp>>
}
以上就是登录的全过程。看到这里,编写一个简单Login功能需要新建四个类,有点麻烦。有没有更便捷的方法的。那肯定!KtArmor 框架还有与之对应 KtArmor-MVP 插件,帮助开发者快速生成对应模板代码(Activity、Presenter、Contract、Model)。
未完待续
这是KtArmor开篇的第一篇。大概讲解了KtArmor基本用法。后续会详细讲解框架的使用、以及插件的使用。至于KtArmor-MVVM 版目前还在测试阶段。后续也会陆续更新。敬请期待吧!
着急的小伙伴可以直接查看下文源码~
最后
KtArmor 框架是一款小而美的框架,也是我个人经验的积累, 总结。如有不妥, 望各位大佬指出。欢迎大家 pr交易, 一起交流学习。
KtArmor-MVP 源码传送门
Kotlin的魔能机甲——KtArmor插件篇(二)
Kotlin的魔能机甲——KtArmor(三)
下次再见