Skip to content

Commit

Permalink
sample: 为ViewModel示例添加更多注释
Browse files Browse the repository at this point in the history
  • Loading branch information
liangjingkanji committed Jul 14, 2023
1 parent 9c1cd73 commit c4d7c4c
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 6 deletions.
6 changes: 6 additions & 0 deletions sample/src/main/java/com/drake/net/sample/constants/Api.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.drake.net.sample.constants


/*
建议请求路径都写在一个单例类中, 方便查找和替换
*/
object Api {
const val HOST = "http://127.0.0.1:8091"

Expand All @@ -9,4 +13,6 @@ object Api {
const val GAME = "/game"
const val DATA = "/data"
const val ARRAY = "/array"
const val CONFIG = "/config"
const val USER_INFO = "/userInfo"
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class MockDispatcher : Dispatcher() {
Api.GAME -> getRawResponse(R.raw.game)
Api.DATA -> getRawResponse(R.raw.data)
Api.ARRAY -> getRawResponse(R.raw.array)
Api.USER_INFO -> getRawResponse(R.raw.user)
Api.CONFIG -> getRawResponse(R.raw.user)
else -> MockResponse().setResponseCode(404)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.drake.net.sample.model


import kotlinx.serialization.Serializable

@Serializable
data class ConfigModel(
var maintain: Boolean = false
)
12 changes: 12 additions & 0 deletions sample/src/main/java/com/drake/net/sample/model/UserInfoModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.drake.net.sample.model


import kotlinx.serialization.Serializable

@Serializable
data class UserInfoModel(
var userId: Int = 0,
var username: String = "",
var age: Int = 0,
var balance: String = ""
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import androidx.fragment.app.viewModels
import com.drake.engine.base.EngineFragment
import com.drake.net.sample.R
import com.drake.net.sample.databinding.FragmentViewModelRequestBinding
import com.drake.net.sample.utils.HttpUtils
import com.drake.net.sample.vm.UserViewModel
import com.drake.net.utils.scopeNetLife

class ViewModelRequestFragment :
EngineFragment<FragmentViewModelRequestBinding>(R.layout.fragment_view_model_request) {

private val userViewModel: UserViewModel by viewModels() // 创建ViewModel

override fun initView() {

// 直接将用户信息绑定到视图上
binding.lifecycleOwner = this
binding.m = userViewModel

Expand All @@ -22,5 +26,12 @@ class ViewModelRequestFragment :
}

override fun initData() {

scopeNetLife {
val configAsync = HttpUtils.getConfigAsync(this)
// 经常使用的请求可以封装函数
val userInfo = HttpUtils.getUser()
configAsync.await() // 实际上在getUser之前就发起请求, 此处只是等待结果, 这就是并发请求
}
}
}
35 changes: 35 additions & 0 deletions sample/src/main/java/com/drake/net/sample/utils/HttpUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.drake.net.sample.utils

import com.drake.net.Get
import com.drake.net.sample.constants.Api
import com.drake.net.sample.model.ConfigModel
import com.drake.net.sample.model.UserInfoModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope


/**
* 常用的请求方法建议写到一个工具类中
*/
object HttpUtils {

/**
* 获取配置信息
*
* 本方法需要再调用await()才会返回结果, 属于异步方法
*/
fun getConfigAsync(scope: CoroutineScope) = scope.Get<ConfigModel>(Api.CONFIG)

/**
* 获取用户信息
* 阻塞返回可直接返回结果
*
* @param userId 如果为空表示请求自身用户信息
*/
suspend fun getUser(userId: String? = null) = coroutineScope {
Get<UserInfoModel>(Api.USER_INFO) {
param("userId", userId)
}.await()
}

}
29 changes: 23 additions & 6 deletions sample/src/main/java/com/drake/net/sample/vm/UserViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,41 @@ import com.drake.net.sample.constants.Api
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope


/**
* 强烈建议不要封装作用域, 封装异步任务即可, 作用域灵活随用随写(Activity/Fragment都可以写作用域)
*
* 不要企图把所有逻辑代码都写在ViewModel中就觉得自己会写MVVM了, 给代码换个位置不叫架构设计, 特别是还增加一堆无效代码情况下
*/
class UserViewModel : ViewModel() {

// 用户信息
var userInfo: MutableLiveData<String> = MutableLiveData()

var updateTime: Long = 0

/**
* 拉取用户信息, 会自动通知页面更新, 同时页面销毁会自动取消网络请求
* 其包含作用域, 生命周期跟随当前viewModel
* scopeNetLife/scopeDialog不推荐写在ViewModel中
* 拉取用户信息, 只能监听返回结果, 仅当外部调用对象不在乎返回结果时使用
* 会自动通知页面更新: 因为使用LiveData将请求结果回调出去, 建议将该liveData对象直接使用DataBinding绑定到页面上, 就会自动触发UI
* 同时页面销毁会自动取消网络请求: 因为他使用`scopeNetLife`. 生命周期跟随当前viewModel
*
* 本质上我并不推荐将Scope定义在ViewModel中(仅仅换个位置要多写很多代码), 特别是妄图在ViewModel中请求网络却要求更新UI
*/
fun fetchUserInfo() = scopeNetLife {
userInfo.value = Get<String>(Api.GAME).await()
updateTime = System.currentTimeMillis()
}

/** 返回Deferred, 可以灵活使用, 支持并发组合 */
fun CoroutineScope.fetchList() = Get<String>(Api.TEST)
/**
* 非阻塞异步任务
* 返回Deferred, 调用await()才会返回结果. 调用即执行任务
*/
fun fetchList(scope: CoroutineScope) = scope.Get<String>(Api.TEST)

/** 直接返回数据, 会阻塞直至数据返回 */
/**
* 阻塞异步任务
* 直接返回结果
*/
suspend fun fetchPrecessData() = coroutineScope {
val response = Get<String>(Api.TEST).await()
response + "处理数据"
Expand Down
3 changes: 3 additions & 0 deletions sample/src/main/res/raw/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"maintain": false
}
6 changes: 6 additions & 0 deletions sample/src/main/res/raw/user.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"userId": 23123132,
"username": "test_account",
"age": 17,
"balance": "123.24"
}

0 comments on commit c4d7c4c

Please sign in to comment.