mirror of
https://github.com/TonyJiangWJ/Auto.js.git
synced 2026-06-12 21:01:32 +08:00
优化canvas 尝试修复悬浮窗中使用canvas在关闭时闪退问题
This commit is contained in:
parent
1c3f3cd705
commit
6718963cd8
@ -16,6 +16,9 @@ import com.stardust.ext.ifNull
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.concurrent.locks.Condition
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2018/3/16.
|
||||
@ -24,11 +27,16 @@ import java.util.concurrent.Executors
|
||||
@SuppressLint("ViewConstructor")
|
||||
class ScriptCanvasView(context: Context, scriptRuntime: ScriptRuntime) : TextureView(context),
|
||||
TextureView.SurfaceTextureListener {
|
||||
@Volatile
|
||||
private var mDrawing = true
|
||||
private val mEventEmitter: EventEmitter = EventEmitter(scriptRuntime.bridges)
|
||||
private val mScriptRuntime: WeakReference<ScriptRuntime>
|
||||
private var mDrawingThreadPool: ExecutorService? = null
|
||||
private val state: AtomicReference<CanvasState>
|
||||
private val lock: ReentrantLock
|
||||
private val resumed: Condition
|
||||
|
||||
private enum class CanvasState {
|
||||
INIT, DRAWING, PAUSE, EXITING, END
|
||||
}
|
||||
|
||||
@Volatile
|
||||
private var mTimePerDraw = (1000 / 30).toLong()
|
||||
@ -39,6 +47,9 @@ class ScriptCanvasView(context: Context, scriptRuntime: ScriptRuntime) : Texture
|
||||
init {
|
||||
surfaceTextureListener = this
|
||||
mScriptRuntime = WeakReference(scriptRuntime)
|
||||
state = AtomicReference(CanvasState.INIT)
|
||||
lock = ReentrantLock()
|
||||
resumed = lock.newCondition()
|
||||
}
|
||||
|
||||
fun setMaxFps(maxFps: Int) {
|
||||
@ -49,37 +60,67 @@ class ScriptCanvasView(context: Context, scriptRuntime: ScriptRuntime) : Texture
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawOnce(scriptCanvas: ScriptCanvas) {
|
||||
var canvas: Canvas? = null
|
||||
lock.lock()
|
||||
try {
|
||||
if (state.get() != CanvasState.DRAWING) {
|
||||
Log.d(LOG_TAG, "canvas state is not drawing ${state.get()}")
|
||||
return
|
||||
}
|
||||
Log.d(LOG_TAG, "canvas draw")
|
||||
val time = SystemClock.uptimeMillis()
|
||||
canvas = lockCanvas()
|
||||
scriptCanvas.setCanvas(canvas)
|
||||
emit("draw", scriptCanvas, this@ScriptCanvasView)
|
||||
if (state.get() != CanvasState.DRAWING) {
|
||||
Log.d(LOG_TAG, "canvas state is not drawing ${state.get()}")
|
||||
return
|
||||
}
|
||||
val dt = mTimePerDraw - (SystemClock.uptimeMillis() - time)
|
||||
if (dt > 0) {
|
||||
sleep(dt)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
mScriptRuntime.get()?.exit(e)
|
||||
state.set(CanvasState.END)
|
||||
} finally {
|
||||
if (canvas != null) {
|
||||
unlockCanvasAndPost(canvas)
|
||||
}
|
||||
lock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun performDraw() {
|
||||
::mDrawingThreadPool.ifNull {
|
||||
Executors.newCachedThreadPool()
|
||||
}.run {
|
||||
execute {
|
||||
var canvas: Canvas? = null
|
||||
var time = SystemClock.uptimeMillis()
|
||||
val scriptCanvas = ScriptCanvas()
|
||||
try {
|
||||
while (mDrawing && !mScriptRuntime.get()?.isStopped!!) {
|
||||
canvas = lockCanvas()
|
||||
scriptCanvas.setCanvas(canvas)
|
||||
emit("draw", scriptCanvas, this@ScriptCanvasView)
|
||||
if (canvas != null) {
|
||||
unlockCanvasAndPost(canvas)
|
||||
val scriptCanvas = ScriptCanvas()
|
||||
while (true) {
|
||||
if (mScriptRuntime.get()?.isStopped == true) {
|
||||
Log.d(LOG_TAG, "performDraw: script runtime stopped ${mScriptRuntime.get()?.isStopped}")
|
||||
break
|
||||
}
|
||||
canvas = null
|
||||
val dt = mTimePerDraw - (SystemClock.uptimeMillis() - time)
|
||||
if (dt > 0) {
|
||||
sleep(dt)
|
||||
try {
|
||||
lock.lock()
|
||||
while (state.get() == CanvasState.PAUSE || state.get() == CanvasState.INIT) {
|
||||
Log.d(LOG_TAG, "canvas draw paused, wait for resume")
|
||||
resumed.await()
|
||||
Log.d(LOG_TAG, "canvas draw resume")
|
||||
}
|
||||
} finally {
|
||||
lock.unlock()
|
||||
}
|
||||
time = SystemClock.uptimeMillis()
|
||||
drawOnce(scriptCanvas)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(LOG_TAG, "performDraw: error $e")
|
||||
mScriptRuntime.get()?.exit(e)
|
||||
mDrawing = false
|
||||
} finally {
|
||||
if (canvas != null) {
|
||||
unlockCanvasAndPost(canvas)
|
||||
}
|
||||
state.set(CanvasState.END)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -99,10 +140,18 @@ class ScriptCanvasView(context: Context, scriptRuntime: ScriptRuntime) : Texture
|
||||
LOG_TAG,
|
||||
"onWindowVisibilityChanged: " + this + ": visibility=" + visibility + ", mDrawingThreadPool=" + mDrawingThreadPool
|
||||
)
|
||||
val oldDrawing = mDrawing
|
||||
mDrawing = visibility == View.VISIBLE
|
||||
if (!oldDrawing && mDrawing) {
|
||||
performDraw()
|
||||
if (visibility == View.VISIBLE) {
|
||||
if (state.compareAndSet(CanvasState.PAUSE, CanvasState.DRAWING)) {
|
||||
lock.lock()
|
||||
try {
|
||||
Log.d(LOG_TAG, "resume canvas draw")
|
||||
resumed.signalAll()
|
||||
} finally {
|
||||
lock.unlock()
|
||||
}
|
||||
}
|
||||
} else if (state.compareAndSet(CanvasState.DRAWING, CanvasState.PAUSE)) {
|
||||
Log.d(LOG_TAG, "pause canvas draw")
|
||||
}
|
||||
super.onWindowVisibilityChanged(visibility)
|
||||
}
|
||||
@ -160,16 +209,37 @@ class ScriptCanvasView(context: Context, scriptRuntime: ScriptRuntime) : Texture
|
||||
}
|
||||
|
||||
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
|
||||
performDraw()
|
||||
Log.d(LOG_TAG, "onSurfaceTextureAvailable: ${this}, width = $width, height = $height")
|
||||
if (state.compareAndSet(CanvasState.INIT, CanvasState.DRAWING)) {
|
||||
Log.d(LOG_TAG, "start drawing")
|
||||
lock.lock()
|
||||
try {
|
||||
performDraw()
|
||||
resumed.signalAll()
|
||||
} finally {
|
||||
lock.unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {}
|
||||
|
||||
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
|
||||
removeAllListeners()
|
||||
mDrawing = false
|
||||
mDrawingThreadPool?.shutdown()
|
||||
val currentStat = state.get()
|
||||
while (
|
||||
currentStat != CanvasState.END && currentStat != CanvasState.EXITING
|
||||
&& !state.compareAndSet(currentStat, CanvasState.EXITING)
|
||||
) {
|
||||
// waiting
|
||||
}
|
||||
lock.lock()
|
||||
try {
|
||||
state.set(CanvasState.END)
|
||||
mDrawingThreadPool?.shutdown()
|
||||
} finally {
|
||||
lock.unlock()
|
||||
}
|
||||
surfaceTextureListener = null
|
||||
setOnTouchListener(null)
|
||||
Log.d(LOG_TAG, "onSurfaceTextureDestroyed: ${this}")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user