继上篇说到, KtArmor-MVP的插件使用。咱们能够快速建立基本的模板代码,可是在编写业务代码时候,不熟悉KtArmor-MVP框架, 不知其然,没法驾驭这个魔能机甲
。因此这篇我先从BaseActivity 开始提及,介绍KtArmor—MVP 的用法,“深刻源码”
解析,带你走进 KtArmor-MVP。android
KtArmor-MVP 框架主要包含3个主要的Activitygit
它们之间继承关系以下:github
MvpActivity > ToolbarActivity > BaseActivity网络
而后咱们来看看他们具体的实现框架
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 在界面未初始化以前调用的初始化窗口
initWidows()
if (initArgs(intent.extras)) {
setContentView(getLayoutId())
initBefore()
initView()
initListener()
initData()
} else {
finish()
}
}
open fun initArgs(bundle: Bundle?): Boolean = true
open fun initWidows() {}
abstract fun getLayoutId(): Int
open fun initBefore() {}
open fun initView() {}
open fun initListener() {}
open fun initData() {}
}
复制代码
BaseActivity
基本的模板结构,定义了基本的Activity 初始化的方法。能够继承BaseActivity,复写对应方法进行扩展。下面是方法具体描述:ide
initWidows
: 在界面(setContentView
)未初始化以前调用的初始化窗口方法initArgs
: 初始化界面参数方法(Activity 之间跳转传递参数), 该方法 默认返回 True
, 显示Activity, 不然返回False, 不显示Activity。getLayoutId
:初始化 Activity 的 layout 布局initBefore
: initView()
以前, setContentView()
方法 以后的初始化方法。initView
:初始化控件view 方法.initListener
:初始化 控件view 相关 listener 方法。initData
:初始化数据方法能够适用于
APP 启动页面
,简单展现页面
等, 不涉及到Presenter 的Activity
函数
abstract class ToolbarActivity : BaseActivity() {
var toolbarTitle: String = ""
set(value) {
field = value
supportActionBar?.title = value
}
override fun initView() {
super.initView()
initToolbar()
}
/** * Toolbar id must be toolbar */
private fun initToolbar() {
findViewById<Toolbar>(R.id.toolbar)?.let { toolbar ->
setSupportActionBar(toolbar)
supportActionBar?.let {
it.setDisplayHomeAsUpEnabled(true)
it.setDisplayShowHomeEnabled(true)
}
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
//将滑动菜单显示出来
android.R.id.home -> {
finish()
return true
}
}
return super.onOptionsItemSelected(item)
}
}
复制代码
ToolbarActivity
继承 BaseActivity, 方便于显示 Toolbar,在项目中挺经常使用的,因此就封装这个Toolbar基本用法。布局
android.R.id.home
)的关闭操做。toolbarTitle
: 能够更改 toolbar 对应的 title在 Activity 的 xml 引入 Toolbar控件, 而且 id 必须为
toolbar
,不然不会调用initToolbar
初始化方法 !!!post
abstract class MvpActivity<P : BaseContract.Presenter> : ToolbarActivity(), BaseContract.View {
lateinit var presenter: P
override fun initBefore() {
presenter = bindPresenter()
}
abstract fun bindPresenter(): P
override fun showError(@StringRes msgRes: Int) {
showError(getString(msgRes))
}
override fun showError(msg: String) {
toast(msg)
hideLoading()
}
override fun showLoading() {}
override fun hideLoading() {}
override fun onDestroy() {
super.onDestroy()
if (::presenter.isInitialized) {
presenter.detachView()
}
}
}
复制代码
MvpActivity 一样是继承ToolbarActivity, 实现了基本 BaseContract.View
, 管理着 Presenter 生命周期
。子类须要实现 bindPresenter()
方法,传递对应的 Presenter。 而后就能够调用 Presenter 进行后续的操做。测试
Presenter
初始化,销毁showError()
, showLoading()
, hideLoading()
等方法。(简单toast 了)
::presenter.isInitialized
意思是判断 Presenter 是否懒加载初始化, 防止未初始化,抛异常。
后续可能会经过泛型T
, 反射生成Presenter,减小重复操做
BaseFragment
、MvpFragment
的实现和 Activity 实现殊途同归,这里就不过多介绍了~
abstract class BasePresenter<V : BaseContract.View>(view: V) : BaseContract.Presenter{
val view: V?
get() = mViewRef.get()
// View 接口类型的弱引用
private var mViewRef = WeakReference(view)
val presenterScope: CoroutineScope by lazy {
CoroutineScope(Dispatchers.Main + Job())
}
fun launchUI(block: suspend CoroutineScope.() -> Unit, error: ((Throwable) -> Unit)? = null) {
presenterScope.launch {
tryCatch({
block()
}, {
error?.invoke(it) ?: view?.showError(it.toString())
})
}
}
override fun detachView() {
mViewRef.clear()
// 取消掉 presenterScope建立的全部协程和其子协程。
presenterScope.cancel()
}
}
复制代码
View
的初始化, 销毁, 采用 弱引用方式, 防止内存泄露。launchUI
封装 协程,切换到 Main线程方法,并进行tryCatch 捕获异常。presenterScope
的销毁,绑定到 对应 UI界面 的 onDestory
方法,防止内存泄露。abstract class BaseModel {
suspend fun <R> launchIO(block: suspend CoroutineScope.() -> R) = withContext(Dispatchers.IO) {
block()
}
}
复制代码
BaseModel 相对简单, 封装了协程切换 IO 线程的操做.
后续可能添加相关 DB 相关操做
class MyRetrofitConfig : BaseRetrofitConfig() {
override val baseUrl: String
get() = API.BASE_URL
override val readTimeOut: Long
get() = //TODO
override val writeTimeOut: Long
get() = //TODO
override val connectTimeOut: Long
get() = //TODO
override fun initRetrofit(): Retrofit {
// 默认实现 BaseRetrofit.init()
return Retrofit.Builder()
.baseUrl(KtArmor.retrofit.baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.client(KtArmor.retrofit.initOkHttpClient())
.build()
}
override fun initOkHttpClient(): OkHttpClient {
// 能够传递 Interceptor 进行网络请求拦截
return BaseOkHttpClient.init(TokenInterceptor.create())
}
}
复制代码
Retrofit 相关网络操做, 能够继承BaseRetrofitConfig
类, 在这里能够配置本身的参数进行扩展, 相关参数以下:
baseUrl
: 网络请求的 baseUrlinitRetrofit
: 为初始化 Retrofit方法,能够返回自定Retrofit
。
BaseRetrofit.init()
initOkHttpClient
初始化 OkHttp的方法,能够返回自定Okhttp
。
BaseOkHttpClient.init()
init()
方法能够传入对应的 Interceptor
, 进行拦截网络操做.readTimeOut
, writeTimeOut
, connectTimeOut
能够复写网络链接超时属性KtArmor-MVP 经过代理方式,封装了 SharedPreferences基本操做.
by Preference
代理key
和对应的 defaultValue
值例如
var account by Preference(Key.ACCOUNT, "")
复制代码
定义了一个 account 变量,传递对应Sp 存储的key,和默认值 “” (空串, 说明account 是 String
类型)
而后直接当正常变量使用, 以下直接赋值 就能够修改 Sp 中key
为 Key.ACCOUNT
的值了。代码以下
account = "123"
复制代码
// 传统的 tryCatch
try{
// TODO
}catch (e: Exception){
// TODO
}
// KtArmor-MVP 扩展
tryCatch({
// TODO
})
// KtArmor-MVP 扩展
tryCatch({
// TODO
}, {
// TODO
})
复制代码
Toast
扩展, 不重复showToast,屡次点击会替换
支持
:Context,Activity, Fragment 扩展扩展参数
:string
(或 @StringRes ), duration
sp
, dp
相互转化
支持
:Float to Float, Int to IntLog
支持
:string.showLog()示例
:"我是Log".showLog()
复制代码
R.color.xxx -> Color Int
,R.drawable.xxx -> Drawable
扩展
支持
:Context,View 下扩展示例
:val defaultColor: Int = context.getColorRef(R.color.xxx)
val defaultDrawable: Drawable? = context.getDrawableRef(R.drawable.xxx)
复制代码
startActivity
参照 anko 的 startActivity (fuzhi)
支持
:Context, Fragment 下扩展示例
:startActivity<XXXActivity>(key to value)
复制代码
View
相关扩展
TextView
扩展
示例
:// 直接获取 TextView 的 text 值
mTvAccount.str()
复制代码
示例
:mIvImage.visible()
复制代码
支持
:View, Activity示例
:activity.hideKeyboard()
复制代码
以上是KtArmor-MVP 的所有内容,后续框架有更新,也会更新相关文档。
仍是那句话,KtArmor-MVP 封装了基本 MVP结构的框架,是一款小而美的框架,麻雀虽小五章俱全。封装了基础的功能,小的项目,或者测试项目能够直接拿来用,省时省力。但愿你们喜欢~
最后,如有不妥,望小伙伴们指出。
感谢阅读,下次再见