简体   繁体   English

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

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

i am working on an online shopping application using retrofit, coroutine, livedata, mvvm,...我正在使用改造、协程、livedata、mvvm 开发在线购物应用程序...
i want to show progress bar before fetching data from server for afew seconds我想在从服务器获取数据几秒钟之前显示进度条
if i have one api request i can show that but in this app i have multiple request如果我有一个 api 请求,我可以显示,但在这个应用程序中,我有多个请求
what should i do in this situation how i should show progress bar??在这种情况下我应该怎么做我应该如何显示进度条?

Api Service接口服务

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

repository存储库

 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
}

VIEWMODEL视图模型

fun getSliderImages() = repository.getSliderImages()

fun getAmazingOffer() = repository.getAmazingOffer()

fun recieveAdvertise() = repository.recieveAdvertise()

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

i will appreciate your help我会感谢你的帮助

I couldn't help but notice that your repository contains lots of repetitive code.我不禁注意到您的存储库包含大量重复代码。 first point to learn here is that all that logic in Repository , it usually goes in the ViewModel .这里要学习的第一点是Repository中的所有逻辑,它通常在ViewModel second thing is that you are using applicationScope to launch your coroutines , which usually is done using viewModelScope (takes care of cancellation) object which is available in every viewModel .第二件事是您正在使用applicationScope来启动您的coroutines ,这通常是使用viewModelScope (负责取消)对象完成的,该对象在每个viewModel可用。

So first we have to take care of that repetitive code and move it to ViewModel .所以首先我们必须处理那些重复的代码并将其移动到ViewModel So your viewModel would now look like所以你的 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()
    }
}

After that remove all the logic from Repository and make it simply call the network methods as之后从Repository中删除所有逻辑并使其简单地调用网络方法

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

And finally to display the progress bar , simply observe the showProgress LiveData object in your Activity / Fragment as最后要显示进度条,只需将Activity / FragmentshowProgress LiveData对象观察为

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

First create a enum class status:首先创建一个枚举类状态:

enum class Status {
SUCCESS,
ERROR,
LOADING
}

Then create resource class like this:然后像这样创建资源类:

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

  }

} 

Now add your request to a list of response:现在将您的请求添加到响应列表中:

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

In your viewmodel class:在您的视图模型类中:

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

Now you can use status to show progress like this .现在您可以使用 status 来显示这样的进度。 use this part in your target fragment:在您的目标片段中使用此部分:

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

I hope you find it useful.希望对你有帮助。

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

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