前言
繼上篇說到, KtArmor-MVP的外掛使用。我們可以快速建立基本的模板程式碼,但是在編寫業務程式碼時候,不熟悉KtArmor-MVP框架, 不知其然,無法駕馭這個魔能機甲
。所以這篇我先從BaseActivity 開始說起,介紹KtArmor—MVP 的用法,“深入原始碼”
解析,帶你走進 KtArmor-MVP。
Activity
KtArmor-MVP 框架主要包含3個主要的Activity
- BaseActivity
- ToolbarActivity
- MvpActivity
它們之間繼承關係如下:
MvpActivity > ToolbarActivity > BaseActivity
然後我們來看看他們具體的實現
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,複寫對應方法進行擴充套件。下面是方法具體描述:
initWidows
: 在介面(setContentView
)未初始化之前呼叫的初始化視窗方法initArgs
: 初始化介面引數方法(Activity 之間跳轉傳遞引數), 該方法 預設返回True
, 顯示Activity, 否則返回False, 不顯示Activity。getLayoutId
:初始化 Activity 的 layout 佈局initBefore
:initView()
之前,setContentView()
方法 之後的初始化方法。initView
:初始化控制元件view 方法.initListener
:初始化 控制元件view 相關 listener 方法。initData
:初始化資料方法
可以適用於
APP 啟動頁面
,簡單展示頁面
等, 不涉及到Presenter 的Activity
ToolbarActivity
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基本用法。
- Toolbar title 的顯示
- Toolbar 返回鍵(
android.R.id.home
)的關閉操作。 toolbarTitle
: 可以更改 toolbar 對應的 title
在 Activity 的 xml 引入 Toolbar控制元件, 並且 id 必須為
toolbar
,否則不會呼叫initToolbar
初始化方法 !!!
MvpActivity
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,減少重複操作
Fragment
BaseFragment
、MvpFragment
的實現和 Activity 實現異曲同工,這裡就不過多介紹了~
Presenter
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
方法,防止記憶體洩露。
Model
abstract class BaseModel {
suspend fun <R> launchIO(block: suspend CoroutineScope.() -> R) = withContext(Dispatchers.IO) {
block()
}
}
複製程式碼
BaseModel 相對簡單, 封裝了協程切換 IO 執行緒的操作.
後續可能新增相關 DB 相關操作
Retrofit
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
: 網路請求的 baseUrl
initRetrofit
: 為初始化 Retrofit方法,可以返回自定Retrofit
。- 預設實現
BaseRetrofit.init()
- 預設實現
initOkHttpClient
初始化 OkHttp的方法,可以返回自定Okhttp
。- 預設實現
BaseOkHttpClient.init()
init()
方法可以傳入對應的Interceptor
, 進行攔截網路操作.readTimeOut
,writeTimeOut
,connectTimeOut
可以複寫網路連線超時屬性
- 預設實現
SharedPreferences
KtArmor-MVP 通過代理方式,封裝了 SharedPreferences基本操作.
- 通過定義一個變數,並通過
by Preference
代理 - 傳遞 Sp的
key
和對應的defaultValue
值
例如
var account by Preference(Key.ACCOUNT, "")
複製程式碼
定義了一個 account 變數,傳遞對應Sp 儲存的key,和預設值 “” (空串, 說明account 是 String
型別)
然後直接當正常變數使用, 如下直接賦值
就可以修改 Sp 中key
為 Key.ACCOUNT
的值了。程式碼如下
account = "123"
複製程式碼
tryCatch
// 傳統的 tryCatch
try{
// TODO
}catch (e: Exception){
// TODO
}
// KtArmor-MVP 擴充套件
tryCatch({
// TODO
})
// KtArmor-MVP 擴充套件
tryCatch({
// TODO
}, {
// TODO
})
複製程式碼
擴充套件函式
Toast
擴充套件, 不重複showToast,多次點選會替換支援
:Context,Activity, Fragment 擴充套件擴充套件引數
:string
(或 @StringRes ),duration
- 全域性 Toast, 通過 Toasts.show(xx)
sp
,dp
相互轉化支援
:Float to Float, Int to Int
Log
支援
: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() 複製程式碼
- View 顯示隱藏擴充套件
示例
:mIvImage.visible() 複製程式碼
- 顯示,關閉軟鍵盤擴充套件
支援
:View, Activity示例
:activity.hideKeyboard() 複製程式碼
- ...
最後
以上是KtArmor-MVP 的全部內容,後續框架有更新,也會更新相關文件。
還是那句話,KtArmor-MVP 封裝了基本 MVP結構的框架,是一款小而美的框架,麻雀雖小五章俱全。封裝了基礎的功能,小的專案,或者測試專案可以直接拿來用,省時省力。希望大家喜歡~
最後,若有不妥,望小夥伴們指出。
KtArmor-MVP 原始碼傳送門
感謝閱讀,下次再見