本文用到的组件:
- ViewModel
- LiveData
- Retrofit
- Coroutine
废话不多说,直接上代码,写个简易框架。
添加依赖
//ViewModel+LiveData+lifecycle && 协程扩展库
def lifecycle_version = "2.2.0"
// ViewModel
api "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
api "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
api "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
BaseViewModel
abstract class BaseViewModel : ViewModel() {
/**
* 协程状态管理
*
* 开始 CoroutineState.START
* 刷新 CoroutineState.REFRESH
* 结束 CoroutineState.FINISH
* 异常 CoroutineState.ERROR
*/
val statusLiveData: MutableLiveData<CoroutineState> by lazy {
MutableLiveData<CoroutineState>()
}
fun launch(refresh: Boolean = true, block: Block) {
viewModelScope.launch {
try {
if (refresh) {
statusLiveData.value = CoroutineState.REFRESH
} else {
statusLiveData.value = CoroutineState.START
}
block()
statusLiveData.value = CoroutineState.FINISH
} catch (e: Exception) {
statusLiveData.value = CoroutineState.ERROR
//处理协程异常
}
}
}
}
Alias.kt
internal typealias Block = suspend CoroutineScope.() -> Unit
CoroutineState
/**
* 协程状态
*/
enum class CoroutineState {
START,
REFRESH,
FINISH,
ERROR
}
BaseActivity
abstract class BaseActivity<T : BaseViewModel> : BaseSimpleActivity() {
protected lateinit var viewModel: T
override fun initViewModel() {
super.initViewModel()
viewModel = createViewModel()
initViewModelActions()
}
private fun initViewModelActions() {
viewModel.statusLiveData.observe(this, Observer { status ->
status?.run {
when (this) {
CoroutineState.START -> {//协程开始
Log.d("coroutine", "开始")
}
CoroutineState.REFRESH -> {//协程开始&&进度菊花圈
Log.d("coroutine", "刷新")
DialogHelper.getInstance().showProgress(this@BaseActivity)
}
CoroutineState.FINISH -> {//协程结束
Log.d("coroutine", "结束")
DialogHelper.getInstance().dismissProgress()
}
CoroutineState.ERROR -> {//协程异常
Log.d("coroutine", "异常")
DialogHelper.getInstance().dismissProgress()
}
}
}
})
}
abstract fun createViewModel(): T
fun launch(block: Block) {
lifecycleScope.launch {
try {
block()
} catch (e: Exception) {
//异常处理
}
}
}
}
BaseSimpleActivity
abstract class BaseSimpleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(getContentView())
initViewModel()
initImmersionBar()
initView(savedInstanceState)
initData(savedInstanceState)
}
private fun initImmersionBar() {
immersionBar {
barColor(R.color.colorPrimary)
}
}
open fun initViewModel(){
}
abstract fun getContentView(): Int
abstract fun initData(savedInstanceState: Bundle?)
abstract fun initView(savedInstanceState: Bundle?)
}
对于ViewmModel和LiveData还不太了解的同学可以移步ViewmModel、LiveData
下面写个示例,请求wanandroid接口。
LoginViewModel
class LoginViewModel : BaseViewModel() {
val contentLiveData: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
fun getChapters() {
launch {
val service = ApiServiceUtil.getApiService<LoginApiService>()
val chapters = withContext(Dispatchers.IO) {
service.getChapters()
}
val json = Gson().toJson(chapters)
contentLiveData.value = json
}
}
}
Retrofit 2.6.0版本之后支持suspend函数无缝对接协程
interface LoginApiService : BaseService {
@GET("/wxarticle/chapters/json")
suspend fun getChapters(): Chapters
}
实体类 Chapters
data class Chapters(
val `data`: List<Data>,
val errorCode: Int,
val errorMsg: String
)
data class Data(
val children: List<Any>,
val courseId: Int,
val id: Int,
val name: String,
val order: Int,
val parentChapterId: Int,
val userControlSetTop: Boolean,
val visible: Int
)
ApiServiceUtil
object ApiServiceUtil {
private val map = mutableMapOf<Class<*>, Any?>()
inline fun <reified T> getApiService() =
getService(T::class.java)
@Suppress("UNCHECKED_CAST")
fun <T> getService(type: Class<T>): T {
return if (map.containsKey(type)) {
map[type] as T
} else {
val temp = Api.getInstance().retrofit.create(type)
map[type] = temp
temp
}
}
}
LoginActivity
class LoginActivity : BaseActivity<LoginViewModel>() {
override fun createViewModel() = ViewModelProvider(this)[LoginViewModel::class.java]
override fun getContentView() = R.layout.activity_login
override fun initData(savedInstanceState: Bundle?) {
}
override fun initView(savedInstanceState: Bundle?) {
viewModel.contentLiveData.observe(this, Observer<String> { content ->
tvLogin.text = content
})
tvLogin.setSingleClick {
viewModel.getChapters()
}
}
}
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.LoginActivity">
<TextView
android:id="@+id/tvLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="5"
android:text="HTTP"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
ending