Reputation: 13883
I have 4 API URL endpoints, in my main activity when the activity show, I will make 4 requests to each endpoint simultaneously. I want to make my request indicator (progress bar) to gone if all that 4 requests is finished successfully or if one of them failed with request code 4xx or 5xx.
So basically I want to perform some action after all requests finish or one of them failed?
In iOS development, I can easily use DispatchGroup
to group some actions and do something after some condition. What is the common way to solve this in Android?
here is the code I use, for simplification, let say I have 2 method to make requests to the server. I am using retrofit:
first, to get products:
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)
}
}
})
}
second, to get banners
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)
}
}
})
}
and then those two methods will be used in Main Activity like this
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)
}
}
}
so, after calling getBanners()
and getProducts()
, I want to hide progress bar, when those 2 request is successful. if failed let say I want to show toast massage ? how to do that ?
java is ok
Upvotes: 2
Views: 2359
Reputation: 790
I'm not familiar with Retrofit but this should work:
create a publicly accessible array; after the completion or failure of each request add the status to this array;
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)
}
}
create a thread(in your activity) which runs a code that check that array all the time until it either contains one failed connection or 4 successful connections; then set the visiblity of your view to gone if this condition is met( in the ui thread);
Thread(Runnable {
while(true){
if(the_public_array.contains_four_success_status()||
the_public_array.contains_one_failure_status()){
[email protected](java.lang.Runnable {
the_progress_bar.set_Visibility(Gone)
})
break;
}
}
}).start();
Upvotes: 0
Reputation: 2119
You can easily achieve this with Retrofit and Coroutines.
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)
}
}
}
GlobalScope.launch {
val firstCall = MyApi().firstCall()
val secondCall= MyApi().secondCall()
val thirdCall= MyApi().thirdCall()
val fourthCall = MyApi().fourthCall()
}
Though using GlobalScope is not good idea, but just to make it quick I written it here, you can create the coroutine scope to make these calls. Again calling 4 different APIs parallel in a single activity or fragment is I don't consider as a good idea. I think you should change your API and make everything in one call.
Hope this helps. Thank You
Upvotes: 1
Reputation: 3193
For achieving this, using Anko is the preferred way if you're using Kotlin
for Android Development.
doAsync {
// ...
}
You can achieve the same with AsyncTask too, and plus it's an Android API
, not a language feature of Java
or Kotlin
. Use AsyncTask
like this:
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)
// ...
}
}
Please follow this link to see how the task responds as the asynchronous task is being executed.
Upvotes: 1