Android協(xié)程和Flow使用記錄

添加依賴

  • Retrofit,聲明式網(wǎng)絡(luò)請(qǐng)求客戶端
  • coroutines-core,協(xié)程核心庫(kù)
  • coroutines-android,協(xié)程安卓適配庫(kù)
  • lifecycle-viewmodel-ktx,ViewModel拓展函數(shù)支持庫(kù)
  • lifecycle-livedata-core-ktx、lifecycle-livedata-ktx,將Flow轉(zhuǎn)換為L(zhǎng)iveData的庫(kù)
// Retrofit
implementation('com.squareup.retrofit2:retrofit:2.9.0')

// 協(xié)程
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0')
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1')

// 使用拓展庫(kù)
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
// ViewModel拓展函數(shù)
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
// 提供lifecycleScope支持
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")

// LiveData拓展函數(shù)
implementation("androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.7")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.7")

基礎(chǔ)封裝

Retrofit管理類

object RetrofitManager {
    private fun getOKHttpClient(timeout: Long): OkHttpClient {
        // 日志打印攔截器
        val logInterceptor = HttpLoggingInterceptor {
            LogTool.d("HttpLoggingInterceptor $it")
        }.setLevel(HttpLoggingInterceptor.Level.BODY)

        val interceptors: MutableList<Interceptor> = ArrayList()

        // 添加自定義攔截器

        val builder = OkHttpClient().newBuilder()
            .callTimeout(timeout, TimeUnit.SECONDS)
            .connectTimeout(timeout, TimeUnit.SECONDS)
            .readTimeout(timeout, TimeUnit.SECONDS)
            .writeTimeout(timeout, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .followRedirects(false)
            .addInterceptor(logInterceptor)

        // 添加攔截器
        builder.interceptors().addAll(interceptors)

        return builder.build()
    }

    private fun getRetrofit(timeout: Long): Retrofit {
        return Retrofit.Builder()
            .client(getOKHttpClient(timeout))
            .baseUrl("apiUrl")
            .addConverterFactory(GsonConvertFactory.create())
            .build()
    }

    fun <T> getService(service: Class<T>, timeout: Long = 10): T {
        return getRetrofit(timeout).create(service)
    }
}

ViewModel基類

typealias block = suspend () -> Unit

open class BaseViewModel : ViewModel(), DefaultLifecycleObserver {
    protected fun launch(
        block: block
    ): Job {
        return viewModelScope.launch {
            try {
                block.invoke()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}

倉(cāng)庫(kù)層基類

open class BaseRepository {
    /**
     * 處理狀態(tài)
     */
    fun <T> BaseResp<T>.handleState(): BaseResp<T> {
        try {
            when (this.code) {
                Constants.HTTP_SUCCESS -> {
                    // 請(qǐng)求成功
                }

                Constants.HTTP_AUTH_INVALID -> {
                    // token過期,清除token,跳轉(zhuǎn)去登錄頁(yè)
                }
            }
        } catch (e: Exception) {
            when (e) {
                is UnknownHostException,
                is HttpException,
                is ConnectException,
                -> {
                    // 網(wǎng)絡(luò)錯(cuò)誤
                }

                else -> {
                }
            }
        }

        return this
    }
}

編寫網(wǎng)絡(luò)層

響應(yīng)結(jié)果的實(shí)體類

class BaseResp<T> {
    var code: Int = -1
    var msg: String = ""
    var data: List<T>? = null

    companion object {
        /**
         * 錯(cuò)誤響應(yīng)
         */
        fun <T> errorResp(): BaseResp<T> {
            return BaseResp<T>().apply {
                code = -1
                msg = "請(qǐng)求失敗,請(qǐng)稍后重試"
                data = null
            }
        }
    }
}

Api接口

interface Api {
    /**
     * 獲取當(dāng)前用戶信息
     */
    @POST("getUserInfo")
    suspend fun getUserInfo(@Body req: BodyReq<EmptyT>): BaseResp<CurrentUserInfo>
    
    /**
     * 保存用戶信息
     */
    @POST("saveUserInfo")
    suspend fun saveUserInfo(@Body req: BodyReq<UserInfo>): BaseResp<*>
    
    /**
     * 獲取App配置
     */
    @POST("getAppConfig")
    suspend fun getAppConfig(@Body req: BodyReq<AppInfo>): BaseResp<AppConfig>
    
    /**
     * 獲取數(shù)據(jù)列表
     */
    @GET("getDataList")
    fun getDataList(): Call<BaseResp<DataList>>
}

Repository倉(cāng)庫(kù)層

/**
 * 用戶信息相關(guān)Repository
 */
open class UserRepository(private val api: Api) : BaseRepository() {
    /**
     * 獲取當(dāng)前用戶信息
     */
    fun getUserInfo(): Flow<BaseResp<CurrentUserInfo>> = flow {
        val result = api.getUserInfo(
            BodyReq()
        ).handleState()
        emit(result)
    }.flowOn(Dispatchers.IO).catch {
        emit(BaseResp.errorResp())
    }

    /**
     * 保存用戶基本信息
     */
    fun saveUserInfo(
        req: UserInfo
    ): Flow<BaseResp<*>> = flow {
        val result = api.saveUserInfo(
            BodyReq()
        ).handleState()
        emit(result)
    }.flowOn(Dispatchers.IO).catch {
        emit(BaseResp.errorResp())
    }
    
    /**
     * 獲取App配置
     */
    fun getAppConfig(
        req: AppInfo
    ): Flow<BaseResp<AppPageConfig>>{
        return flow {
            val resp = api.getAppConfig(req).handleState()
            emit(resp)
        }.flowOn(Dispatchers.IO).catch {
            emit(BaseResp.errorResp())
        }
    }
}

ViewModel層

/**
 * 用戶信息ViewModel
 */
open class UserInfoViewModel(private val repo: UserInfoRepository) : BaseViewModel() {
    val appConfigLiveData = MutableLiveData<AppPageConfig>>()

    /**
     * 獲取當(dāng)前用戶信息
     */
    fun getUserInfo() = liveData {
        emit(repo.getUserInfo().single())
    }

    /**
     * 保存用戶基本信息
     */
    fun saveUserInfo(req: UserInfo) = liveData {
        emit(repo.saveUserInfo(req).single())
    }
    
    /**
     * 獲取App配置
     */
    fun getAppConfig(req: AppInfo) = launch {
        repo.getAppConfig(req).collect{value->
            appConfigLiveData.value = value.data
        }
    }
}

ViewModel管理類

object ViewModelManager {
    private val mApi by lazy {
        RetrofitManager.getService(Api::class.java, 45)
    }
    
    class UserInfoViewModelFactory(
        private val repo: UserInfoRepository
    ) : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            if (modelClass.isAssignableFrom(UserInfoViewModel::class.java)) {
                return UserInfoViewModel(repo) as T
            } else {
                throw IllegalArgumentException("Unknown ViewModel Class")
            }
        }
    }
    
    /**
     * 獲取用戶信息的ViewModel
     */
    fun getUserInfoViewModel(
        owner: ViewModelStoreOwner
    ): UserInfoViewModel {
        val repo = UserInfoRepository(mApi)
        ViewModelProvider(
            owner,
            UserInfoViewModelFactory(repo)
        )[UserInfoViewModel::class.java]
    }
}

基礎(chǔ)使用

ViewModelManager.getUserInfoViewModel()
    .saveUserInfo(req)
    .observe(
        lifecycleOwner,
        object : BaseObserver<UserInfo>() {
            override fun getRespDataSuccess(it: PResDataEmptyT) {
                super.getRespDataSuccess(it)
                // 獲取用戶信息成功
            }

        override fun getRespDataEnd(code: Int, errorMsg: String) {
                super.getRespDataEnd(code, errorMsg)
                // 獲取用戶信息失敗
            }
})

直接在Activity、Fragment中使用

  • 不帶生命周期控制
private val mainScope: CoroutineScope = MainScope()

mainScope.launch {
    withContext(Dispatchers.IO) {
        val appConfig = repo.getAppConfig(req)
        appConfigLiveData.postValue(appConfig)
    }
}
  • 帶生命周期控制
lifecycleScope.launch {
    try {
        // 發(fā)起請(qǐng)求
        getDataList()
    } catch (e: Exception) {
        // 處理異常情況
        e.printStackTrace()
        hideLoading()
    }
}

private suspend fun getDataList() {
    try {
        val response = withContext(Dispatchers.IO) {
            request.getDataList().execute()
        }
        if (response.isSuccessful) {
            val body = response.body()
            // 請(qǐng)求成功
        }
    } catch (e: Exception) {
        // 處理異常
        e.printStackTrace()
    } finally {
        hideLoading()
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容