面试题答案
一键面试设计思路
- 创建协程作用域:使用
CoroutineScope
来管理协程的生命周期,通常在ViewModel
中创建。 - 发起异步网络请求:利用
async
函数在协程中发起异步网络请求,每个async
调用返回一个Deferred
对象。 - 等待所有请求完成:使用
awaitAll
函数等待所有Deferred
对象完成,即所有网络请求完成。 - 更新UI:在所有请求完成后,切换到主线程(通过
withContext(Dispatchers.Main)
)来更新UI。
核心代码示例
假设使用Retrofit
进行网络请求,以下是核心代码:
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import kotlinx.coroutines.*
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
// Retrofit API 接口定义
interface ApiService {
@GET("example")
suspend fun getExampleData(): String
}
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
val textView = findViewById<TextView>(R.id.textView)
viewModel.fetchData().observe(this) { data ->
textView.text = data
}
}
}
class MainViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> get() = _data
private val retrofit = Retrofit.Builder()
.baseUrl("https://example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
private val apiService = retrofit.create(ApiService::class.java)
fun fetchData(): LiveData<String> {
viewModelScope.launch {
try {
val deferred1 = async { apiService.getExampleData() }
val deferred2 = async { apiService.getExampleData() }
val result1 = deferred1.await()
val result2 = deferred2.await()
val combinedResult = result1 + result2
withContext(Dispatchers.Main) {
_data.value = combinedResult
}
} catch (e: Exception) {
e.printStackTrace()
}
}
return data
}
}
协程相比传统线程和AsyncTask的优势
- 代码简洁:协程使用更简洁的语法来处理异步操作,通过
await
、async
等函数代替传统线程的复杂同步机制和AsyncTask
的繁琐回调。 - 轻量级:协程是轻量级线程,相比传统线程,创建和销毁的开销更小,适合大量异步任务的场景。
- 易于管理:通过
CoroutineScope
可以方便地管理协程的生命周期,避免内存泄漏等问题。而传统线程在Activity或Fragment销毁时可能需要手动管理线程的停止,AsyncTask
也存在类似的生命周期管理问题。 - 非阻塞:协程在挂起时不会阻塞线程,能够更高效地利用线程资源,提高应用的响应性。传统线程在执行I/O等操作时可能会阻塞线程,导致UI卡顿。
AsyncTask
虽然也是异步的,但在处理复杂异步逻辑时不够灵活。