【问题标题】:show progress bar before fetching data from server using retrofit在使用改造从服务器获取数据之前显示进度条
【发布时间】:2021-07-27 16:30:23
【问题描述】:

我正在使用改造、协程、livedata、mvvm、...
我想在从服务器获取数据几秒钟之前显示进度条
如果我有一个 api 请求,我可以显示,但在这个应用程序中我有多个请求
在这种情况下我应该怎么做我应该如何显示进度条??

API 服务

 @GET("homeslider.php")
suspend fun getSliderImages(): Response<List<Model.Slider>>

@GET("amazingoffer.php")
suspend fun getAmazingProduct(): Response<List<Model.AmazingProduct>>

@GET("handsImages.php")
suspend fun getHandsFreeData(
    @Query(
        "handsfree_id"
    ) handsfree_id: Int
): Response<List<Model.HandsFreeImages>>

@GET("handsfreemoreinfo.php")
suspend fun gethandsfreemoreinfo(): Response<List<Model.HandsFreeMore>>


@GET("wristmetadata.php")
suspend fun getWristWatchMetaData(
    @Query(
        "wrist_id"
    ) wrist_id: Int
): Response<List<Model.WristWatch>>

存储库

 fun getSliderImages(): LiveData<List<Model.Slider>> {
    val data = MutableLiveData<List<Model.Slider>>()
    val job = Job()
    applicationScope.launch(IO + job) {
        val response = api.getSliderImages()
        withContext(Main + SupervisorJob(job)) {
            data.value = response.body()
        }
        job.complete()
        job.cancel()
    }
    return data
}

fun getAmazingOffer(): LiveData<List<Model.AmazingProduct>> {
    val data = MutableLiveData<List<Model.AmazingProduct>>()
    val job = Job()
    applicationScope.launch(IO + job) {
        val response = api.getAmazingProduct()
        withContext(Main + SupervisorJob(job)) {
            data.value = response.body()
        }
        job.complete()
        job.cancel()
    }
    return data
}

fun getHandsFreeData(handsree_id: Int): LiveData<List<Model.HandsFreeImages>> {

    val dfData = MutableLiveData<List<Model.HandsFreeImages>>()

    val job = Job()
    applicationScope.launch(IO + job) {


        val response = api.getHandsFreeData(handsree_id)

        withContext(Main + SupervisorJob(job)) {
            dfData.value = response.body()

        }
        job.complete()
        job.cancel()

    }
    return dfData
}

fun getHandsFreeMore(): LiveData<List<Model.HandsFreeMore>> {

    val data = MutableLiveData<List<Model.HandsFreeMore>>()
    val job = Job()
    applicationScope.launch(IO + job) {

        val response = api.gethandsfreemoreinfo()


        withContext(Main + SupervisorJob(job)) {

            data.value = response.body()

        }
        job.complete()
        job.cancel()
    }

    return data
}

视图模型

fun getSliderImages() = repository.getSliderImages()

fun getAmazingOffer() = repository.getAmazingOffer()

fun recieveAdvertise() = repository.recieveAdvertise()

fun dailyShoes(context: Context) = repository.getDailyShoes(context)

感谢您的帮助

【问题讨论】:

  • 如果你有3个api请求,在不同的地方,你可以有3个进度条
  • 我有 4 个主要片段。家庭组合篮简介,我每个人至少有 4 个 api。我想在从服务器获取所有数据之前显示进度条。例如,当您启动应用程序时,您只会看到一个空白片段中的进度条,然后在几秒钟后,所有回收器和视图都会出现@Ticherhaz FreePalestine

标签: java android kotlin


【解决方案1】:

首先创建一个枚举类状态:

enum class Status {
SUCCESS,
ERROR,
LOADING
}

然后像这样创建资源类:

data class Resource<out T>(val status: Status, val data: T?, val message: String?) {

companion object {

    fun <T> success(data: T?): Resource<T> {
        return Resource(Status.SUCCESS, data, null)
    }

    fun <T> error(msg: String, data: T?): Resource<T> {
        return Resource(Status.ERROR, data, msg)
    }

    fun <T> loading(data: T?): Resource<T> {
        return Resource(Status.LOADING, data, null)
    }

  }

} 

现在将您的请求添加到响应列表中:

var list = java.util.ArrayList<Response<*>>()
suspend fun getApis() = list.addAll(
    listOf(
        api.advertise(),
        api.getAmazingProduct(),
        api.dailyShoes(),
        api.getSliderImages(),
         .
         .
         .
    )
)

在您的视图模型类中:

private val _apis = MutableLiveData<Resource<*>>()
val apis: LiveData<Resource<*>>
    get() = _apis

init {
    getAllApi()
}

fun getAllApi() {
    val job = Job()
    viewModelScope.launch(IO + job) {
        _apis.postValue(
            Resource.loading(null)
        )
        delay(2000)
        repository.getApis().let {
            withContext(Main + SupervisorJob(job)) {
                it.let {
                    if (it) {
                        _apis.postValue(Resource.success(it))
                    } else {
                        _apis.postValue(Resource.error("Unknown error eccured", null))
                    }
                }
            }
        }
        job.complete()
        job.cancel()
    }
}

现在您可以像这样使用状态来显示进度。在你的目标片段中使用这部分:

 private fun setProgress() {
    viewModel.apis.observe(viewLifecycleOwner) {
        when (it.status) {
            Status.SUCCESS -> {
                binding.apply {
                    progress.visibility = View.INVISIBLE
                    line1.visibility = View.VISIBLE
                    parentscroll.visibility = View.VISIBLE
                }
            }
            Status.ERROR -> {
                binding.apply {
                    progress.visibility = View.INVISIBLE
                    line1.visibility = View.INVISIBLE
                    parentscroll.visibility = View.INVISIBLE
                }
            }
            Status.LOADING -> {
                binding.apply {
                    progress.visibility = View.VISIBLE
                    line1.visibility = View.INVISIBLE
                    parentscroll.visibility = View.INVISIBLE
                }
            }
        }
    }
}

希望对你有用。

【讨论】:

    【解决方案2】:

    我不禁注意到您的存储库包含大量重复代码。这里要学习的第一点是Repository 中的所有逻辑,它通常在ViewModel 中。第二件事是您使用applicationScope 来启动您的coroutines,这通常是使用viewModelScope(负责取消)对象完成的,该对象在每个viewModel 中都可用。

    所以首先我们必须处理那些重复的代码并将其移至ViewModel。所以你的 viewModel 现在看起来像

    class YourViewModel: ViewModel() {
        // Your other init code, repo creation etc
    
        // Live data objects for progressBar and error, we will observe these in Fragment/Activity
        val showProgress: MutableLiveData<Boolean> = MutableLiveData()
        val errorMessage: MutableLiveData<String> = MutableLiveData()
    
        /**
          * A Generic api caller, which updates the given live data object with the api result 
          * and internally takes care of progress bar visibility. */
        private fun <T> callApiAndPost(liveData: MutableLiveData<T>,
                                       apiCall: () -> Response<T> ) = viewModelScope.launch {
            try{
                showProgress.postValue(true)   // Show prgress bar when api call is active
                if(result.code() == 200) { liveData.postValue(result.body())  }
                else{ errorMessage.postValue("Network call failed, try again") }
                showProgress.postValue(false)
            }
            catch (e: Exception){
                errorMessage.postValue("Network call failed, try again")
                showProgress.postValue(false)
            }
        }
        
        /******** Now all your API call methods should be called as *************/
    
        // First declare the live data object which will contain the api result
        val sliderData: MutableLiveData<List<Model.Slider>> = MutableLiveData()
    
        // Now call the API as
        fun getSliderImages() = callApiAndPost(sliderData) {
            repository.getSliderImages()
        }
    }
    

    之后从Repository 中删除所有逻辑并使其简单地调用网络方法

    suspend fun getSliderImages() = api.getSliderImages()   // simply delegate to network layer
    

    最后要显示进度条,只需观察Activity/Fragment 中的showProgress LiveData 对象

    viewModel.showProgress.observer(this, Observer{
        progressBar.visibility = if(it) View.VISIBLE else View.GONE
    }
    

    【讨论】:

    • 感谢您的帮助,但是主页片段中有很多方法。应该有一种方法可以合并所有结果,然后在合并结果后使用您的方法。 callApiandPost@mightyWOZ
    猜你喜欢
    • 1970-01-01
    • 2020-08-14
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 2012-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多