pull/2341/head
kunfei 2 years ago
parent 6f6039259d
commit 385658cc60
  1. 28
      app/src/main/java/io/legado/app/help/TTS.kt
  2. 8
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  3. 18
      app/src/main/java/io/legado/app/utils/HandlerUtils.kt
  4. 6
      app/src/main/java/io/legado/app/utils/RegexExtensions.kt

@ -4,14 +4,19 @@ import android.speech.tts.TextToSpeech
import android.speech.tts.UtteranceProgressListener import android.speech.tts.UtteranceProgressListener
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppLog import io.legado.app.constant.AppLog
import io.legado.app.utils.buildMainHandler
import io.legado.app.utils.splitNotBlank import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import splitties.init.appCtx import splitties.init.appCtx
class TTS { class TTS {
private val handler by lazy { buildMainHandler() }
private val tag = "legado_tts" private val tag = "legado_tts"
private val clearTtsRunnable = Runnable { clearTts() }
private var textToSpeech: TextToSpeech? = null private var textToSpeech: TextToSpeech? = null
private var text: String? = null private var text: String? = null
@ -24,20 +29,19 @@ class TTS {
TTSUtteranceListener() TTSUtteranceListener()
} }
@Synchronized
fun speak(text: String) { fun speak(text: String) {
handler.removeCallbacks(clearTtsRunnable)
this.text = text this.text = text
if (textToSpeech == null) { if (textToSpeech == null) {
textToSpeech = TextToSpeech(appCtx, initListener)
} else { } else {
addTextToSpeakList()
}
} }
private fun initTts() {
textToSpeech == TextToSpeech(appCtx, initListener)
} }
private fun clearTts() { @Synchronized
fun clearTts() {
textToSpeech?.let { tts -> textToSpeech?.let { tts ->
tts.stop() tts.stop()
tts.shutdown() tts.shutdown()
@ -72,6 +76,7 @@ class TTS {
override fun onInit(status: Int) { override fun onInit(status: Int) {
if (status == TextToSpeech.SUCCESS) { if (status == TextToSpeech.SUCCESS) {
textToSpeech?.setOnUtteranceProgressListener(utteranceListener) textToSpeech?.setOnUtteranceProgressListener(utteranceListener)
addTextToSpeakList()
} else { } else {
appCtx.toastOnUi(R.string.tts_init_failed) appCtx.toastOnUi(R.string.tts_init_failed)
} }
@ -85,15 +90,18 @@ class TTS {
private inner class TTSUtteranceListener : UtteranceProgressListener() { private inner class TTSUtteranceListener : UtteranceProgressListener() {
override fun onStart(utteranceId: String?) { override fun onStart(utteranceId: String?) {
TODO("Not yet implemented") //开始朗读取消释放资源任务
handler.removeCallbacks(clearTtsRunnable)
} }
override fun onDone(utteranceId: String?) { override fun onDone(utteranceId: String?) {
TODO("Not yet implemented") //一分钟没有朗读释放资源
handler.postDelayed(clearTtsRunnable, 60000L)
} }
@Deprecated("Deprecated in Java")
override fun onError(utteranceId: String?) { override fun onError(utteranceId: String?) {
TODO("Not yet implemented")
} }
} }

@ -431,13 +431,13 @@ class ReadBookActivity : BaseReadBookActivity(),
if (event.action == MotionEvent.ACTION_SCROLL) { if (event.action == MotionEvent.ACTION_SCROLL) {
val axisValue = event.getAxisValue(MotionEvent.AXIS_VSCROLL) val axisValue = event.getAxisValue(MotionEvent.AXIS_VSCROLL)
LogUtils.d("onGenericMotionEvent", "axisValue = $axisValue") LogUtils.d("onGenericMotionEvent", "axisValue = $axisValue")
mainHandler.removeCallbacks(nextPageRunnable) binding.root.removeCallbacks(nextPageRunnable)
mainHandler.removeCallbacks(prevPageRunnable) binding.root.removeCallbacks(prevPageRunnable)
// 获得垂直坐标上的滚动方向 // 获得垂直坐标上的滚动方向
if (axisValue < 0.0f) { // 滚轮向下滚 if (axisValue < 0.0f) { // 滚轮向下滚
mainHandler.postDelayed(nextPageRunnable, 200) binding.root.postDelayed(nextPageRunnable, 200)
} else { // 滚轮向上滚 } else { // 滚轮向上滚
mainHandler.postDelayed(prevPageRunnable, 200) binding.root.postDelayed(prevPageRunnable, 200)
} }
return true return true
} }

@ -10,20 +10,14 @@ import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** This main looper cache avoids synchronization overhead when accessed repeatedly. */ /** This main looper cache avoids synchronization overhead when accessed repeatedly. */
@JvmField private val mainLooper: Looper = Looper.getMainLooper()
val mainLooper: Looper = Looper.getMainLooper()
@JvmField private val mainThread: Thread = mainLooper.thread
val mainThread: Thread = mainLooper.thread
val isMainThread: Boolean inline get() = mainThread === Thread.currentThread() private val isMainThread: Boolean inline get() = mainThread === Thread.currentThread()
@PublishedApi fun buildMainHandler(): Handler {
internal val currentThread: Any? return if (SDK_INT >= 28) Handler.createAsync(mainLooper) else try {
inline get() = Thread.currentThread()
val mainHandler: Handler by lazy {
if (SDK_INT >= 28) Handler.createAsync(mainLooper) else try {
Handler::class.java.getDeclaredConstructor( Handler::class.java.getDeclaredConstructor(
Looper::class.java, Looper::class.java,
Handler.Callback::class.java, Handler.Callback::class.java,
@ -35,6 +29,8 @@ val mainHandler: Handler by lazy {
} }
} }
private val mainHandler by lazy { buildMainHandler() }
fun runOnUI(function: () -> Unit) { fun runOnUI(function: () -> Unit) {
if (isMainThread) { if (isMainThread) {
function() function()

@ -9,6 +9,8 @@ import splitties.init.appCtx
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException import kotlin.coroutines.resumeWithException
private val handler by lazy { buildMainHandler() }
/** /**
* 带有超时检测的正则替换 * 带有超时检测的正则替换
* 超时重启apk,线程不能强制结束,只能重启apk * 超时重启apk,线程不能强制结束,只能重启apk
@ -24,14 +26,14 @@ suspend fun CharSequence.replace(regex: Regex, replacement: String, timeout: Lon
block.resumeWithException(e) block.resumeWithException(e)
} }
} }
mainHandler.postDelayed(timeout) { handler.postDelayed(timeout) {
if (coroutine.isActive) { if (coroutine.isActive) {
val timeoutMsg = "替换超时,3秒后还未结束将重启应用\n替换规则$regex\n替换内容:${this}" val timeoutMsg = "替换超时,3秒后还未结束将重启应用\n替换规则$regex\n替换内容:${this}"
val exception = RegexTimeoutException(timeoutMsg) val exception = RegexTimeoutException(timeoutMsg)
block.cancel(exception) block.cancel(exception)
appCtx.longToastOnUi(timeoutMsg) appCtx.longToastOnUi(timeoutMsg)
CrashHandler.saveCrashInfo2File(exception) CrashHandler.saveCrashInfo2File(exception)
mainHandler.postDelayed(3000) { handler.postDelayed(3000) {
if (coroutine.isActive) { if (coroutine.isActive) {
appCtx.restart() appCtx.restart()
} }

Loading…
Cancel
Save