【发布时间】:2018-12-20 20:09:50
【问题描述】:
我已经编写了适合我需要的扩展函数:
suspend fun AsyncLayoutInflater.inflateSuspended(@LayoutRes resid: Int, parent: ViewGroup?): View {
return suspendCoroutine { continuation ->
inflate(resid, parent) { view, _, parent ->
continuation.resume(view)
}
}
}
但我不确定如何在不阻塞 UI 的情况下使用它。我尝试了 Dispatchers.IO,但我得到 RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
我应该如何使用这个功能?
更新:我发现 inflate 不会冻结 UI,但 addView 会。 calendarHolder 在 ScrollView 内。在 calendarView 显示在屏幕上之前,滚动冻结。
val inflater = AsyncLayoutInflater(this)
val startTime = System.currentTimeMillis()
coroutineScope.launch {
val startTimeInside = System.currentTimeMillis()
repeat(100) {
calendarView = inflater.inflateSuspended(R.layout.layout_calendar, calendarHolder)
as MaterialCalendarView
}
val addViewStart = System.currentTimeMillis()
calendarHolder.addView(calendarView)
val endTimeInside = System.currentTimeMillis()
Timber.i("inflate: ${endTimeInside - startTimeInside}")
Timber.i("addView: ${endTimeInside - addViewStart}")
setupCalendar()
}
val endTime = System.currentTimeMillis()
Timber.i("outside: ${endTime - startTime}")
即使日志显示:
外部:2 膨胀:2105 添加视图:5
【问题讨论】:
-
根据定义,它不会阻塞 UI,那么为什么需要协程呢?
AsyncLayoutInflater.OnInflateFinishedListener将在mainThread上异步执行 -
现在,我正在扩充日历,并在
OnInflateFinishedListener中发出网络请求以填充该日历的事件。我打算对它们使用异步等待。 -
不要直接从监听器发出阻塞网络请求。将其设置为协程后,在
withContext(Dispatchers.IO)块内进行网络调用。这与在IO中启动整个协程不同。 -
@osrl 我更新了回答以使用 Volley 发出网络请求,并包含一秒的延迟以表明 UI 从未被阻塞
-
感谢@MarkoTopolnik,但这已经是我正在做的事情了。实际上,如果我在回调中进行网络调用,它会抛出
NetworkOnMainThreadException
标签: android kotlin layout-inflater kotlinx.coroutines