前言
从下面可以看到使用Flow后,数据处理更加自由,如果数据处理逻辑相对复杂更推荐使用Flow。
不使用Flow
ViewModel基类
BaseViewModel.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext
open class BaseViewModel : ViewModel() { var mShowMsg = mutableStateOf(false) var mShowMsgContent = mutableStateOf("") var isLoading = mutableStateOf(false)
fun mLaunch(block: suspend () -> Unit) { viewModelScope.launch(Dispatchers.IO) { try { block() } catch (e: Exception) { withContext(Dispatchers.Main) { e.printStackTrace() isLoading.value = false mShowMsg.value = true mShowMsgContent.value = "数据加载失败" } } } } }
|
ViewModel实现
UserViewModel.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import android.util.Log import androidx.compose.runtime.mutableStateListOf import com.google.gson.Gson import com.xhkjedu.zxs_android.api.ApiManager import com.xhkjedu.zxs_android.model.UserItem import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext
class UserViewModel : BaseViewModel() { private val TAG = "UserViewModel" val userList = mutableStateListOf<UserItem>()
fun loadUserList() { mLaunch { val result = ApiManager.userService.getUserList().body() Log.i("API", Gson().toJson(result)) withContext(Dispatchers.Main) { result?.let { Log.i(TAG, "Thread: " + Thread.currentThread().name) Log.i(TAG, "UserViewModel: " + Gson().toJson(it)) if (it.code == 0) { if (it.obj == null) { it.obj = mutableListOf() } userList.addAll(it.obj) mShowMsg.value = false } else { mShowMsg.value = true mShowMsgContent.value = it.msg } } } } } }
|
使用Flow
ViewModel基类
BaseViewModel.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import retrofit2.Response import java.io.IOException import java.net.SocketException
sealed class NetworkResult<out T> { data class Success<out T>(val data: T) : NetworkResult<T?>() data class Error( val message: String, val exception: Exception? = null ) : NetworkResult<Nothing>()
object Loading : NetworkResult<Nothing>() }
open class BaseViewModel : ViewModel() { var mShowMsg = mutableStateOf(false) var mShowMsgContent = mutableStateOf("") var isLoading = mutableStateOf(false)
@Suppress("UNCHECKED_CAST") fun <T> getFlow(reqBlock: suspend () -> Response<T>): Flow<NetworkResult<T>> { return flow { emit(NetworkResult.Loading)
try { val result = reqBlock() val data = result.body() if (data != null) { emit(NetworkResult.Success(data)) } else { emit(NetworkResult.Error("请求数据失败")) } } catch (e: Exception) { emit(NetworkResult.Error("请求数据失败")) } } .catch { e -> val errorMsg = when (e) { is SocketException -> "网络连接失败" is IOException -> "数据读取失败" else -> "请求处理异常: ${e.message}" } emit(NetworkResult.Error(errorMsg)) } .flowOn(Dispatchers.IO) as Flow<NetworkResult<T>> }
@Suppress("UNCHECKED_CAST") fun <T> mLaunch( reqBlock: suspend () -> Response<T>, successBlock: suspend (data: T) -> Unit ) { viewModelScope.launch { getFlow(reqBlock) .collect { result -> when (result) { is NetworkResult.Loading -> { isLoading.value = true mShowMsg.value = false }
is NetworkResult.Success<*> -> { isLoading.value = false mShowMsg.value = false val data = result.data data?.let { successBlock(it as T) } }
is NetworkResult.Error -> { isLoading.value = false mShowMsg.value = true mShowMsgContent.value = result.message } } } } } }
|
ViewModel实现
UserViewModel.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import android.util.Log import androidx.compose.runtime.mutableStateListOf import com.google.gson.Gson import com.xhkjedu.zxs_android.api.ApiManager import com.xhkjedu.zxs_android.model.UserItem
class UserViewModel : BaseViewModel() { private val TAG = "UserViewModel" val userList = mutableStateListOf<UserItem>()
fun loadUserListUseFlow() { mLaunch(suspend { ApiManager.userService.getUserList() }) { data -> Log.i(TAG, "UserViewModel: " + Gson().toJson(data)) data.obj?.let { userList.addAll(it) } } } }
|
相关
数据实体
ResultVo.kt
1 2 3 4 5
| data class ResultVo<T>( val code: Int, val msg: String, val obj: T? )
|
这个非必要,接收的时候可以使用ResultVo<Collection<UserItem>>替代。
ResultListVo.kt
1 2 3 4 5
| class ResultListVo<T> { var code: Int = 0 var msg: String = "" var obj: MutableList<T>? = null }
|
服务层
ServiceUser.kt
1 2 3 4 5 6 7 8 9
| import com.xhkjedu.zxs_android.model.ResultVo import com.xhkjedu.zxs_android.model.UserItem import retrofit2.Response import retrofit2.http.GET
interface ServiceUser { @GET("userlist.json") suspend fun getUserList(): Response<ResultVo<Collection<UserItem>>> }
|
也可以这样写
1 2 3 4 5 6 7 8 9
| import com.xhkjedu.zxs_android.model.ResultListVo import com.xhkjedu.zxs_android.model.UserItem import retrofit2.Response import retrofit2.http.GET
interface ServiceUser { @GET("userlist.json") suspend fun getUserList(): Response<ResultListVo<UserItem>> }
|
管理层
ApiManager.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| import android.annotation.SuppressLint import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.security.SecureRandom import java.util.concurrent.TimeUnit import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLContext import javax.net.ssl.TrustManager import javax.net.ssl.X509TrustManager
object ApiManager { private lateinit var userRetrofit: Retrofit
lateinit var userService: ServiceUser
@SuppressLint("CustomX509TrustManager") fun getUnsafeOkHttpClient(): OkHttpClient { try { val trustAllCerts = arrayOf<TrustManager>(
object : X509TrustManager { override fun checkClientTrusted( chain: Array<out java.security.cert.X509Certificate>?, authType: String? ) { }
override fun checkServerTrusted( chain: Array<out java.security.cert.X509Certificate>?, authType: String? ) { }
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> = arrayOf() } )
val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, trustAllCerts, SecureRandom())
val allHostsValid = HostnameVerifier { _, _ -> true }
return OkHttpClient.Builder() .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager) .hostnameVerifier(allHostsValid) .build() } catch (e: Exception) { throw RuntimeException(e) } }
init { if (!::userRetrofit.isInitialized) { val client = getUnsafeOkHttpClient().newBuilder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .writeTimeout(20, TimeUnit.SECONDS) .addInterceptor(HeaderInterceptor()) .build();
userRetrofit = Retrofit.Builder() .baseUrl("https://www.psvmc.cn/") .client(client) .addConverterFactory(GsonConverterFactory.create()) .build() }
if (!::userService.isInitialized) { userService = userRetrofit.create(ServiceUser::class.java) } } }
|
请求头切面
HeaderInterceptor.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import android.util.Log import com.xhkjedu.zxs_android.common.CommonData.deviceModel import com.xhkjedu.zxs_android.common.CommonData.loginUser import com.xhkjedu.zxs_android.utils.ZDeviceUtils import okhttp3.Interceptor import okhttp3.Response import java.io.IOException
class HeaderInterceptor : Interceptor { var TAG: String = "HeaderInterceptor"
@Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val systemModel = ZDeviceUtils.getSystemModel() Log.i(TAG, "intercept: " + systemModel) val original = chain.request() try { val mBuilder = original.newBuilder() if (loginUser != null) { mBuilder.header("XH-UserId", loginUser!!.getUserid().toString() + "") }
val request = mBuilder .header("XH-DeviceModel", deviceModel()) .method(original.method, original.body) .build()
return chain.proceed(request) } catch (e: Exception) { return chain.proceed(original) } } }
|