簡體   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