利用handlerThread,在子线程渲染SurfaceView的canvas。
class MySurfaceView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : SurfaceView(context, attrs, defStyleAttr), SurfaceHolder.Callback, Handler.Callback {
companion object {
private const val MSG_POST_WHAT = 888
private const val MSG_RENDER_WHAT = 999
private const val DEFAULT_RENDER_TIME = 16
}
var renderTime = DEFAULT_RENDER_TIME
@Volatile
private var mCanRun = false
private lateinit var mHandlerThread: HandlerThread
private lateinit var mHandler: Handler
private val taskList = mutableListOf<Model>()
private val evaluator = PointFEvaluator(PointF())
private val mMatrix = Matrix()
init {
setZOrderOnTop(true)
holder.setFormat(PixelFormat.TRANSLUCENT)
holder.addCallback(this)
}
fun postTask(model: Model) {
if (!mCanRun) {
return
}
val msg = mHandler.obtainMessage(MSG_POST_WHAT)
msg.obj = model
mHandler.sendMessageAtFrontOfQueue(msg)
}
override fun surfaceCreated(holder: SurfaceHolder) {
mHandlerThread = HandlerThread("xxx")
mHandlerThread.start()
mHandler = Handler(mHandlerThread.looper, this)
mCanRun = true
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
mCanRun = true
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
if (mCanRun) {
mHandlerThread.quit()
taskList.clear()
}
mCanRun = false
}
override fun handleMessage(msg: Message): Boolean {
val curMillis = SystemClock.uptimeMillis()
if (!mCanRun) return true
if (msg.what == MSG_POST_WHAT) { // 提交新任务
taskList.add(msg.obj as Model)
if (!mHandler.hasMessages(MSG_RENDER_WHAT)) {
mHandler.sendEmptyMessage(MSG_RENDER_WHAT)
}
} else if (msg.what == MSG_RENDER_WHAT) { // 渲染任务
val canvas = holder.lockCanvas() ?: return true
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
val hashTask = taskList.isNotEmpty()
if (hashTask) {
val iterator = taskList.listIterator()
while (iterator.hasNext()) {
val model = iterator.next()
model.updateFraction(curMillis)
model.draw(canvas)
if (model.isCompleted) { // 任务完成
iterator.remove()
}
}
}
holder.unlockCanvasAndPost(canvas)
if (hashTask) { // 是否还有渲染任务
// 保持60帧
mHandler.sendEmptyMessageDelayed(MSG_RENDER_WHAT, renderTime.minus(SystemClock.uptimeMillis() - curMillis).minus(3).coerceAtLeast(0))
}
}
return true
}
private fun Model.draw(canvas: Canvas) {
val pointF = getBitmapPointF(evaluator)
mMatrix.reset()
if (scale != null) {
mMatrix.postScale(scale, scale)
}
mMatrix.postTranslate(pointF.x, pointF.y)
canvas.drawBitmap(bitmap, mMatrix, null)
}
}
data class Model(
val bitmap: Bitmap,
val from: PointF,
val to: PointF,
val duration: Long,
val scaleSize: Size? = null,
) {
val scale = scaleSize?.let {
it.width.toFloat().div(bitmap.width).coerceAtMost(it.height.toFloat().div(bitmap.height))
}
private val readerWidth = scale?.times(bitmap.width)?.toInt() ?: bitmap.width
private val readerHeight = scale?.times(bitmap.height)?.toInt() ?: bitmap.height
private var firstFrame = -1L
private var fraction = 0f
fun updateFraction(curMillis: Long) {
if (firstFrame == -1L) {
firstFrame = curMillis
} else {
fraction = curMillis.minus(firstFrame).toFloat().div(duration)
if (fraction > 1f) {
fraction = 1f
}
}
}
val isCompleted: Boolean
get() = fraction >= 1f
fun getBitmapPointF(evaluator: PointFEvaluator): PointF {
return evaluator.evaluate(fraction, from, to).also {
it.set(it.x.minus(readerWidth.div(2)), it.y.minus(readerHeight.div(2)))
}
}
}