同时调用多个API,并在相应请求的处理完成后立即更新UI [英] Multiple API calls Simultaneously and update UI as soon as the processing of the corresponding request finishes Android

查看:163
本文介绍了同时调用多个API,并在相应请求的处理完成后立即更新UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要同时运行 6个API调用,并且需要在相应请求完成后为每个API更新UI

I need to run 6 API calls Simultaneously and need to update the UI for each when corresponding request finishes

当前,我正在使用 kotlin协程并行执行 ,并使用以下代码

Currently I am using kotlin coroutines parallel execution using the following code

    suspend fun getAllData() : List<String>{
    return withContext(Dispatchers.IO) {

        lateinit var getObject1Task: Deferred<Response<String>>
        lateinit var getObject2Task: Deferred<Response<String>>
        lateinit var getObject3Task: Deferred<Response<String>>

        lateinit var getObject4Task: Deferred<Response<String>>
        lateinit var getObject5Task: Deferred<Response<String>>
        lateinit var getObjec6Task: Deferred<Response<String>>

        launch {
            getObject1Task = dataApiService.getData()
            getObject2Task = dataApiService.getData()
            getObject3Task = dataApiService.getData()
            getObject4Task = dataApiService.getData()
            getObject5Task = dataApiService.getData()
            getObject6Task = dataApiService.getData()
        }

          var stringList = ArrayList<String >()

        stringList.add(getObject1Task.await().body()!!) /// add All to the list
        stringList
    }
}

我无法找到一种方法来在API完成后立即获取每个字符串的数据. 我还尝试了 LiveData ,但是有些方法是有意义的.

I am unable to find a way a way to get data for each string as soon as that API finishes. I also tried LiveData but some how that was making any sense.

每个字符串之间都没有链接,因此在列表中添加所有字符串不是必需的

Each String has no link with the other so it not essential to add all strings in a list

推荐答案

使用协程,有多种方法可以实现此目的.这里有两个例子:

Using coroutines, there are multiple ways to achieve this. Here are 2 examples:

  1. 使用 launch 而不返回值,并直接从中更新UI 在协程中,一旦字符串准备就绪.
  2. 类似于您的方法,您还可以使用 async ,等待 将来的响应返回值,然后更新UI.
  1. Use launch without returning a value and directly update UI from within the coroutine, once the string is ready.
  2. Similar to your approach, you can also use async, wait for the future response return value and then update UI.

示例1:忘了,在每个元素准备就绪后直接更新UI

从协程内部更新UI元素时,应使用Dispatchers.Main作为协程上下文.

When updating UI elements from within a coroutine, you should use Dispatchers.Main as coroutine context.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)


    repeat(6){index ->
        val id = resources.getIdentifier("tv${index+1}", "id", packageName)
        val textView = findViewById<TextView>(id)
        textViews.add(textView)
    }

    repeat(6){ index ->
        GlobalScope.launch(Dispatchers.Main) { // launch coroutine in the main thread
            val apiResponseTime = Random.nextInt(1000, 10000)
            delay(apiResponseTime.toLong())
            textViews[index].text = apiResponseTime.toString()
        }
    }
}

注意: 在这里,字符串准备就绪后,每个TextView都会立即更新,而不会阻塞主线程. 我在LinearLayout中使用了6个示例TextView,它们的ID为"tv1","tv2" ...

Note: Here, every TextView gets updated as soon as the string is ready, without blocking the main thread. I used 6 example TextViews in a LinearLayout with IDs "tv1", "tv2"...

示例2:使用并行async + await(),在完成所有作业(与您的作业类似)后更新UI

在这里,我们将并行启动6个async,并在准备好结果后立即将其添加到列表中.添加最后一个结果后,我们将返回列表并循环更新TextView.

Here we are launching 6 async in parallel and add the results to the list as soon as they are ready. When the last result is added, we return the list and update the TextViews in a loop.

val textViews = mutableListOf<TextView>()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    repeat(6){index ->
        val id = resources.getIdentifier("tv${index+1}", "id", packageName)
        val textView = findViewById<TextView>(id)
        textViews.add(textView)
    }
    // note: again we use Dispatchers.Main context to update UI
    GlobalScope.launch(Dispatchers.Main) {
        val strings = updateUIElementAfterThisFinishes()
        repeat(6){index ->
            textViews[index].text = strings[index]
        }
    }

}

 // for API calls we use Dispatchers.IO context, this function will finish at 10 seconds or less
suspend fun updateUIElementAfterThisFinishes(): List<String> = withContext(Dispatchers.IO){
    val strings = mutableListOf<String>()
    val jobs = Array(6){GlobalScope.async {
        val apiResponseTime = Random.nextInt(1000, 10000)
        delay(apiResponseTime.toLong())
        apiResponseTime.toString()
    }}
    jobs.forEach {
        strings.add(it.await())
    }
    return@withContext strings
}

这篇关于同时调用多个API,并在相应请求的处理完成后立即更新UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆