Как выполнить действие после завершения всех сетевых запросов или одного из них? - PullRequest
2 голосов
/ 14 июня 2019

У меня есть 4 конечных точки URL API, в своей основной деятельности, когда активность показывает, я сделаю 4 запроса к каждой конечной точке одновременно.Я хочу, чтобы индикатор моего запроса (индикатор выполнения) пропал, если все эти 4 запроса были успешно завершены или если один из них завершился неудачно с кодом запроса 4xx или 5xx.

Так что в основном я хочу выполнить какое-то действие после всехзапросы заканчиваются или один из них не выполнен?

В разработке для iOS я легко могу использовать DispatchGroup, чтобы сгруппировать некоторые действия и сделать что-то после некоторого условия.Какой общий способ решить эту проблему в Android?

Вот код, который я использую, для упрощения, скажем, у меня есть 2 метода для отправки запросов на сервер.Я использую модификацию:

сначала, чтобы получить продукты:

fun getProductsFromServer(customerID: String, type: String = "", categoryID: String = "" , completion: (errorMessage: String?, products: ArrayList<Product>?) -> Unit) {

            val lakuinAPI = RetrofitHandler.getInstance(LakuinAPI::class.java)
            val call = lakuinAPI.getProductData("1","0","0","100000000000",type = type,customer_id = customerID,categories_id = categoryID)

            call.enqueue(object: Callback<ProductData> {

                override fun onFailure(call: Call<ProductData>, t: Throwable) {
                    completion("Failed to make netwroking call : ${t.localizedMessage}", null)
                }

                override fun onResponse(call: Call<ProductData>, response: Response<ProductData>) {

                    val productList = ArrayList<Product>()

                    if (!response.isSuccessful) {
                        completion("Error: ${response.code()}",productList)
                        return
                    }

                    val jsonProductData = response.body() ?: return
                    val statusSuccess = jsonProductData.success

                    if (statusSuccess == "1") {

                        val products = jsonProductData.product_data
                        completion(null,products)

                    } else if (statusSuccess == "0") {

                        val errorMessageFromServer = jsonProductData.message
                        completion(errorMessageFromServer,productList)


                    }


                }


            })
        }

секунду, чтобы получить баннеры

fun getBannersFromServer(completion: (errorMessage: String?, banners: ArrayList<Banner>?) -> Unit) {

            val lakuinAPI = RetrofitHandler.getInstance(LakuinAPI::class.java)
            val call = lakuinAPI.getBanners()

            call.enqueue(object : Callback<BannerData> {

                override fun onFailure(call: Call<BannerData>, t: Throwable) {
                    completion("Failed to make netwroking call : ${t.localizedMessage}", null)
                }

                override fun onResponse(call: Call<BannerData>, response: Response<BannerData>) {

                    val bannerList = ArrayList<Banner>()

                    if (!response.isSuccessful()) {
                        completion("Error: ${response.code()}",bannerList)
                        return
                    }

                    val jsonBannerData = response.body() ?: return
                    val statusSuccess = jsonBannerData.success

                    if (statusSuccess == "1") {

                        val banners = jsonBannerData.data
                        completion(null,banners)

                    } else if (statusSuccess == "0") {
                        val errorMessageFromServer = jsonBannerData.message
                        completion(errorMessageFromServer,bannerList)


                    }

                }


            })




        }

, а затем эти два метода будут использоваться в MainАктивность, подобная этой

private fun getProducts(type: String) {

        Product.getProductsFromServer(customerID = userData.id.toString(), type = type) { errorMessage, products ->

            errorMessage?.let {
                activity?.toast(it)
            } ?: run {

                val productList = products ?: ArrayList()
                setUpRecyclerView(type = type,products = productList)

            }


        }

    }


    private fun getBanners() {


        Banner.getBannersFromServer { errorMessage, banners ->

            errorMessage?.let {
                activity?.toast(it)
            } ?: run {
                val bannerList = banners ?: ArrayList()
                setUpImageSlideShow(banners = bannerList)
            }


        }
    }

, поэтому после вызова getBanners() и getProducts() я хочу скрыть индикатор выполнения, когда эти 2 запроса выполнены успешно.если не удалось, скажем, я хочу показать тост массаж?как это сделать?

Ява в порядке

Ответы [ 3 ]

1 голос
/ 14 июня 2019

Вы можете легко достичь этого с помощью Retrofit и сопрограмм.

Шаг 1 Создайте вызовы для модернизации

interface MyApi{

    @GET("end-point}")
    suspend fun firstCall(): Response<YourModelClassForResponse>

    @GET("end-point}")
    fun secondCall(): Response<YourModelClassForResponse>

    @GET("end-point}")
    fun thirdCall(): Response<YourModelClassForResponse>

    @GET("end-point}")
    fun fourthCall(): Call<YourModelClassForResponse>


    companion object {
        private const val BASE_URL = "bas url"
        operator fun invoke(): SmartFarmApi {
            return Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(BASE_URL)
                .build().create(MyApi::class.java)
        }
    }
}

Шаг 2 Вызовите свои API с помощью сопрограмм

    GlobalScope.launch { 
      val firstCall =  MyApi().firstCall()
      val secondCall=  MyApi().secondCall()
      val thirdCall=  MyApi().thirdCall()
      val fourthCall =  MyApi().fourthCall()
    }

Хотя использование GlobalScope не очень хорошая идея, но просто сделать это быстроЯ написал это здесь, вы можете создать область сопрограмм для выполнения этих вызовов.Опять же, вызывая 4 разных API параллельно в одном действии или фрагменте, я не считаю хорошей идеей.Я думаю, что вы должны изменить свой API и сделать все за один вызов.

Надеюсь, это поможет.Спасибо

1 голос
/ 14 июня 2019

Для достижения этого, использование Anko является предпочтительным способом, если вы используете Kotlin для разработки Android.

doAsync {
    // ...
}

Вы можете добиться того же с помощью AsyncTask , плюс плюс это Android API, а не языковая функция Java или Kotlin,Используйте AsyncTask следующим образом:

class someTask() : AsyncTask<Void, Void, String>() {
    override fun doInBackground(vararg params: Void?): String? {
        // ...
    }

    override fun onPreExecute() {
        super.onPreExecute()
        // ...
    }

    override fun onProgressUpdate(vararg text: String?) {
        super.onPostExecute(result)
        // ...
    }

    override fun onPostExecute(result: String?) {
        super.onPostExecute(result)
        // ...
    }
}

Перейдите по этой ссылке , чтобы увидеть, как задача реагирует на выполнение асинхронной задачи.

0 голосов
/ 14 июня 2019

Я не знаком с Retrofit, но это должно работать:

создать общедоступный массив; после завершения или сбоя каждого запроса добавьте статус в этот массив;

override fun onFailure(call: Call<BannerData>, t: Throwable) {
                completion("Failed to make netwroking call : ${t.localizedMessage}", null)
                the_public_array.add("failure");
}
override fun onResponse(call: Call<BannerData>, response: Response<BannerData>) {
                val bannerList = ArrayList<Banner>()
                if (!response.isSuccessful()) {
                    the_public_array.add("failure")
                    completion("Error: ${response.code()}",bannerList)
                    return
                }
                val jsonBannerData = response.body() ?: return
                val statusSuccess = jsonBannerData.success
                if (statusSuccess == "1") {
                    the_public_array.add("success")
                    val banners = jsonBannerData.data
                    completion(null,banners)
                } else if (statusSuccess == "0") {
                    the_public_array.add("failure")
                    val errorMessageFromServer = jsonBannerData.message
                    completion(errorMessageFromServer,bannerList)
                }

            }

создать поток (в вашей деятельности), который запускает код, который постоянно проверяет этот массив, пока он не содержит одно неудачное соединение или 4 успешных соединения; затем установите видимость вашего просмотра как пропавшую, если это условие выполнено (в потоке пользовательского интерфейса);

Thread(Runnable {
    while(true){
        if(the_public_array.contains_four_success_status()||
                the_public_array.contains_one_failure_status()){
            this@MainActivity.runOnUiThread(java.lang.Runnable { 
                the_progress_bar.set_Visibility(Gone) 
            }) 
            break;
         }
    }
}).start();
...