如何解决Jetpack Compose 定期更新并在另一个线程中绘制作为 SurfaceView
如何在 Jetpack Compose 中实现 SurfaceView 的对应物,与另一个线程一起使用以在特定时间间隔内绘制和更新?
和协程我像这样使用它
abstract class CoroutineSurfaceView : SurfaceView,SurfaceHolder.Callback,DefaultLifecycleObserver {
// Handle works in thread that exception is caught that are
private val handler = CoroutineExceptionHandler { coroutineContext,throwable ->
}
internal lateinit var canvas: Canvas
var framePerSecond = 60
private var renderTime = 100L / framePerSecond
private val coroutineScope = CoroutineScope(handler + SupervisorJob() + Dispatchers.Default)
private lateinit var job: Job
private lateinit var surfaceHolder: SurfaceHolder
constructor(context: Context,attrs: AttributeSet?) : super(context,attrs) {
init(context)
}
constructor(context: Context) : super(context) {
init(context)
}
open fun init(context: Context) {
surfaceHolder = this.holder
surfaceHolder.addCallback(this)
setZOrderOnTop(true)
}
override fun surfaceCreated(holder: SurfaceHolder) {
}
override fun surfaceChanged(holder: SurfaceHolder,format: Int,width: Int,height: Int) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
}
private fun startCoroutineRendering() {
job = coroutineScope.launch {
while (isActive) {
if (!surfaceHolder.surface.isValid) {
continue
}
canvas = surfaceHolder.lockCanvas()
update()
render(canvas)
holder.unlockCanvasAndPost(canvas)
delay(renderTime)
}
}
}
internal abstract fun update()
internal abstract fun render(canvas: Canvas)
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
startCoroutineRendering()
}
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
coroutineScope.launch(Dispatchers.Main.immediate) {
job.cancelAndJoin()
}
}
}
解决方法
@Composable
fun EachFrameUpdatingCanvas(modifier: Modifier,onDraw: DrawScope.(Long) -> Unit) {
var frameTime by remember { mutableStateOf(0L) }
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(Unit) {
lifecycleOwner.whenStarted {
while (true) {
// this will be called for each frame
// by updating `remember` value we initiating EachFrameUpdatingCanvas redraw
frameTime = withFrameMillis { it }
}
}
}
Canvas(modifier = modifier) {
// you had to use frameTime somewhere in EachFrameUpdatingCanvas
// otherwise it won't be redrawn. But you don't have to pass it to `onDraw` if you don't want
onDraw(frameTime)
}
}
像这样使用它:
EachFrameUpdatingCanvas(Modifier.fillMaxSize()) { frameTime ->
drawCircle(
Color.Black,radius = size.minDimension / 2.0f * (frameTime % 100) / 100f,)
}
在 compose 中绘制是在后台完成的,但是如果您在绘制过程中进行一些繁重的计算(在 DrawScope
内),您可能需要用 AndroidView 包裹您的 CoroutineSurfaceView
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。