繼上篇說到, 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結構的框架,是一款小而美的框架,麻雀雖小五章俱全。封裝了基礎的功能,小的項目,或者測試項目能夠直接拿來用,省時省力。但願你們喜歡~
最後,如有不妥,望小夥伴們指出。
感謝閱讀,下次再見