Surface has already been released: при рисовании с помощью Canvas
Моя программа рисует овал когда мы нажимаем на экран и + меняет координаты овала в зависимости от координат удерживаемого пальца. Когда палец отпускаем, овал должен исчезнуть.
Сейчас когда я нажимаю на экран то получаю свой овал и + когда перемещаю палец то овал всегда рядом с ним, но когда я отпускаю палец то получаю ошибку:
E/Surface: freeAllBuffers: 1 buffers were freed while being dequeued!
E/AndroidRuntime: FATAL EXCEPTION: Thread-2
Process: com.example.lab10, PID: 24198
java.lang.IllegalStateException: Surface has already been released.
at android.view.Surface.checkNotReleasedLocked(Surface.java:774)
at android.view.Surface.unlockCanvasAndPost(Surface.java:473)
> at android.view.SurfaceView$1.unlockCanvasAndPost(SurfaceView.java:1629)
> at com.example.lab10.TaskSix$OvalsView.surfaceCreated$lambda$0(TaskSix.kt:136)
> at com.example.lab10.TaskSix$OvalsView.$r8$lambda$fxYnyciEdLkjDqbt7r8jlbaJ-60(Unknown Source:0)
>at com.example.lab10.TaskSix$OvalsView$$ExternalSyntheticLambda0.run(Unknown Source:2)
>at java.lang.Thread.run(Thread.java:1012)
package com.example.lab10
import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.DisplayMetrics
import android.util.Log
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.View
import android.view.WindowManager
import androidx.constraintlayout.widget.ConstraintLayout
class TaskSix : AppCompatActivity() {
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_task_six)
title = "Task#6"
val layout = findViewById<ConstraintLayout>(R.id.layout)
val ovalsView = OvalsView(this)
layout.setOnTouchListener(View.OnTouchListener { view, motionEvent ->
when (motionEvent.getActionMasked()) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
Log.d("qqq", "down")
val ID: Int = motionEvent.getPointerId(motionEvent.getActionIndex())
Log.d("qqq", "element with id: $ID")
layout.addView(ovalsView)
}
MotionEvent.ACTION_MOVE -> {
Log.d("qqq", "move")
var idx = 0
while (idx < motionEvent.pointerCount) {
val ID: Int = motionEvent.getPointerId(idx) // pobranie unikalnego id dla każdego dotyku
idx++
ovalsView._top = motionEvent.y
ovalsView._left = motionEvent.x
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
Log.d("qqq", "up")
layout.removeView(ovalsView)
}
else -> Log.d("qqq", "unhandled")
}
return@OnTouchListener true
})
}
private class OvalsView(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
private val mSurfaceHolder: SurfaceHolder
private val mPainter = Paint()
private var mDrawingThread: Thread? = null
private val mDisplay = DisplayMetrics()
private var mDisplayWidth: Int
private var mDisplayHeight: Int
private var mRotation = 0f
var _top: Float = 0f
var _left: Float = 0f
init {
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
wm.defaultDisplay.getMetrics(mDisplay)
mDisplayWidth = mDisplay.widthPixels
mDisplayHeight = mDisplay.heightPixels
mPainter.isAntiAlias = true
mPainter.color = Color.RED
mSurfaceHolder = holder
mSurfaceHolder.addCallback(this)
}
private fun animateOvals(): Boolean {
mRotation += 1
return true
}
private fun drawWheel(canvas: Canvas) {
canvas.drawColor(Color.WHITE)
// canvas.rotate(mRotation, mDisplayWidth / 2f, mDisplayHeight / 2f)
//drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)
// canvas.drawOval(mDisplayWidth/2f - 100f/2f - 100f, mDisplayHeight/2 + 100f/2f,
// mDisplayWidth/2f + 100f/2f + 100f, mDisplayHeight/2f - 100/2f, mPainter)
if (_top > 0f && _left > 0f)
canvas.drawOval(_left, _top, _left + 200f, _top + 350f, mPainter)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
mDisplayWidth = w
mDisplayHeight = h
super.onSizeChanged(w, h, oldw, oldh)
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
if (mDrawingThread != null) {
mDrawingThread!!.interrupt()
}
}
override fun surfaceCreated(holder: SurfaceHolder) {
mDrawingThread = Thread(Runnable {
var MAX_FRAME_TIME = 1000/60
var frameStartTime = System.nanoTime();
var frameTime: Long = 0
var canvas: Canvas? = null
while (!Thread.currentThread().isInterrupted && animateOvals()) {
canvas = mSurfaceHolder.lockCanvas()
if (canvas != null) {
drawWheel(canvas)
mSurfaceHolder.unlockCanvasAndPost(canvas)
}
frameTime = (System.nanoTime() - frameStartTime) / 1000000
if (frameTime < MAX_FRAME_TIME) // faster than the max fps - limit the FPS
{
try {
Thread.sleep(MAX_FRAME_TIME - frameTime)
} catch (e: InterruptedException) {
// ignore
}
}
}
})
mDrawingThread!!.start()
}
}
}