繁体   English   中英

在使用改造从服务器获取数据之前显示进度条

[英]show progress bar before fetching data from server using retrofit

我正在使用改造、协程、livedata、mvvm 开发在线购物应用程序...
我想在从服务器获取数据几秒钟之前显示进度条
如果我有一个 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)

我会感谢你的帮助

我不禁注意到您的存储库包含大量重复代码。 这里要学习的第一点是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 / FragmentshowProgress LiveData对象观察为

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

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

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()
    }
}

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

 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
                }
            }
        }
    }
}

希望对你有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM