I've written this extension function which suits my needs:
suspend fun AsyncLayoutInflater.inflateSuspended(@LayoutRes resid: Int, parent: ViewGroup?): View {
return suspendCoroutine { continuation ->
inflate(resid, parent) { view, _, parent ->
continuation.resume(view)
}
}
}
But I'm not sure how I should use it without blocking UI. I tried Dispatchers.IO but I got RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
How should I use this function?
Update: I discovered that inflate
doesn't freeze the UI but addView does. calendarHolder
is inside a ScrollView
. Scrolling freezes right before calendarView is shown in the screen.
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}")
Even if log shows this:
outside: 2 inflate: 2105 addView: 5
Like I mentioned in my comment, AsyncLayoutInflater
is by definition asynchronous, and is mandatory to create the instance in the main thread, that's why you get an error if you change the Dispatcher
. Nevertheless, it is possible to convert the callback-style to a coroutine style.
Example: updated to show the composition of coroutines
class MainActivity : AppCompatActivity(), CoroutineScope {
private val activityJob = Job()
private lateinit var requestQueue: RequestQueue
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + activityJob
suspend fun AsyncLayoutInflater.inflate(@LayoutRes resid: Int, parent: ViewGroup?): View =
suspendCoroutine { continuation -> inflate(resid, parent) { view, _, _ -> continuation.resume(view) } }
suspend fun getTodo(id: Int): String = suspendCoroutine { continuation ->
val request = StringRequest(Request.Method.GET, "https://jsonplaceholder.typicode.com/todos/$id",
Response.Listener { continuation.resume(it) },
Response.ErrorListener { continuation.resumeWithException(it) }
)
requestQueue.add(request)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
requestQueue = Volley.newRequestQueue(this)
val parent = findViewById<ViewGroup>(R.id.frameLayout)
val asyncLayoutInflater = AsyncLayoutInflater(this)
launch {
val view = asyncLayoutInflater.inflate(R.layout.async_layout, parent) as TextView
parent.addView(view)
delay(1000)
val todo = getTodo(1)
view.text = todo
}
}
override fun onDestroy() {
super.onDestroy()
activityJob.cancel()
requestQueue.cancelAll { true }
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.