设计协程层级结构
- 顶层协程:在应用的顶层,如
Application
类中,可以创建一个CoroutineScope
,用于管理整个应用生命周期内的协程。
class MyApplication : Application() {
val applicationScope = CoroutineScope(Job() + Dispatchers.Default)
override fun onCreate() {
super.onCreate()
// 例如启动一个长期运行的任务
applicationScope.launch {
while (true) {
// 执行任务
delay(1000)
}
}
}
override fun onTerminate() {
super.onTerminate()
applicationScope.cancel()
}
}
- 界面相关协程:在每个界面(Activity或Fragment)中,创建与界面生命周期绑定的
CoroutineScope
。例如在Activity
中:
class MainActivity : AppCompatActivity() {
private val activityScope = CoroutineScope(Job() + Dispatchers.Main)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
activityScope.launch {
// 执行与界面相关的异步任务,如网络请求更新UI
val result = withContext(Dispatchers.IO) {
// 模拟网络请求
delay(2000)
"Network result"
}
textView.text = result
}
}
override fun onDestroy() {
super.onDestroy()
activityScope.cancel()
}
}
处理协程异常
- try - catch 块:在协程内部使用
try - catch
块捕获异常。
val scope = CoroutineScope(Dispatchers.IO)
scope.launch {
try {
// 可能抛出异常的异步操作
val result = someSuspendingFunctionThatMightThrow()
// 处理结果
} catch (e: Exception) {
// 处理异常
Log.e("CoroutineError", "Exception in coroutine: ${e.message}")
}
}
- 全局异常处理:可以通过
CoroutineExceptionHandler
来设置全局的异常处理。
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
Log.e("GlobalCoroutineError", "Unhandled exception: ${exception.message}")
}
val scope = CoroutineScope(Job() + Dispatchers.Default + exceptionHandler)
scope.launch {
// 不捕获异常的协程代码
throw RuntimeException("Simulated exception")
}
实现高效的异步数据流动
- Flow:使用
Flow
来处理异步数据流。例如,从网络请求获取数据并实时更新UI。
class DataRepository {
fun fetchDataFlow(): Flow<String> = flow {
// 模拟网络请求
delay(2000)
emit("Data from network")
}
}
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.dataFlow.collect { data ->
textView.text = data
}
}
}
class MainViewModel : ViewModel() {
val dataFlow = DataRepository().fetchDataFlow()
.flowOn(Dispatchers.IO)
.catch { e ->
// 处理异常
Log.e("FlowError", "Exception in flow: ${e.message}")
}
}
- Channel:用于在协程之间传递数据。例如,生产者 - 消费者模式。
val channel = Channel<Int>()
val producer = CoroutineScope(Dispatchers.Default).launch {
for (i in 1..10) {
channel.send(i)
delay(1000)
}
channel.close()
}
val consumer = CoroutineScope(Dispatchers.Default).launch {
for (item in channel) {
Log.d("Consumer", "Received: $item")
}
}
避免内存泄漏
- 绑定生命周期:如前面在
Activity
和Fragment
中创建与生命周期绑定的CoroutineScope
,在界面销毁时取消协程,避免内存泄漏。
- 谨慎使用全局变量:避免在协程中持有对界面等短生命周期对象的全局引用。如果需要在协程中使用界面相关对象,通过参数传递,并在协程内部进行空值检查。
class MainActivity : AppCompatActivity() {
private val activityScope = CoroutineScope(Job() + Dispatchers.Main)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
activityScope.launch {
val textView = findViewById<TextView>(R.id.textView)
textView?.let {
// 使用textView
}
}
}
override fun onDestroy() {
super.onDestroy()
activityScope.cancel()
}
}