diff --git a/app/src/main/java/io/legado/app/api/controller/SourceController.kt b/app/src/main/java/io/legado/app/api/controller/SourceController.kt index f4a92cd6d..80dd7d783 100644 --- a/app/src/main/java/io/legado/app/api/controller/SourceController.kt +++ b/app/src/main/java/io/legado/app/api/controller/SourceController.kt @@ -5,9 +5,9 @@ import android.text.TextUtils import io.legado.app.api.ReturnData import io.legado.app.data.appDb import io.legado.app.data.entities.BookSource +import io.legado.app.help.BookSourceAnalyzer import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonArray -import io.legado.app.utils.fromJsonObject import io.legado.app.utils.msg object SourceController { @@ -23,8 +23,9 @@ object SourceController { fun saveSource(postData: String?): ReturnData { val returnData = ReturnData() + postData ?: return returnData.setErrorMsg("数据不能为空") kotlin.runCatching { - val bookSource = GSON.fromJsonObject(postData) + val bookSource = BookSourceAnalyzer.jsonToBookSource(postData) if (bookSource != null) { if (TextUtils.isEmpty(bookSource.bookSourceName) || TextUtils.isEmpty(bookSource.bookSourceUrl)) { returnData.setErrorMsg("书源名称和URL不能为空") diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 7f50e1546..d31efc649 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -8,8 +8,6 @@ import android.content.Intent import android.content.IntentFilter import android.graphics.BitmapFactory import android.media.AudioManager -import android.os.Handler -import android.os.Looper import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.annotation.CallSuper @@ -29,6 +27,10 @@ import io.legado.app.ui.book.read.page.entities.TextChapter import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.postEvent import io.legado.app.utils.toastOnUi +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import splitties.init.appCtx abstract class BaseReadAloudService : BaseService(), @@ -44,7 +46,6 @@ abstract class BaseReadAloudService : BaseService(), } } - internal val handler = Handler(Looper.getMainLooper()) private lateinit var audioManager: AudioManager private var mFocusRequest: AudioFocusRequestCompat? = null private var broadcastReceiver: BroadcastReceiver? = null @@ -56,7 +57,7 @@ abstract class BaseReadAloudService : BaseService(), internal var readAloudNumber: Int = 0 internal var textChapter: TextChapter? = null internal var pageIndex = 0 - private val dsRunnable: Runnable = Runnable { doDs() } + private var dsJob: Job? = null override fun onCreate() { super.onCreate() @@ -69,7 +70,7 @@ abstract class BaseReadAloudService : BaseService(), initBroadcastReceiver() upNotification() upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) - startDs() + doDs() } override fun onDestroy() { @@ -149,7 +150,7 @@ abstract class BaseReadAloudService : BaseService(), upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) postEvent(EventBus.ALOUD_STATE, Status.PAUSE) ReadBook.uploadProgress() - startDs() + doDs() } @CallSuper @@ -184,7 +185,7 @@ abstract class BaseReadAloudService : BaseService(), private fun setTimer(minute: Int) { timeMinute = minute - startDs() + doDs() } private fun addTimer() { @@ -194,32 +195,34 @@ abstract class BaseReadAloudService : BaseService(), timeMinute += 10 if (timeMinute > 180) timeMinute = 180 } - startDs() - } - - private fun startDs() { - postEvent(EventBus.TTS_DS, timeMinute) - upNotification() - handler.removeCallbacks(dsRunnable) - handler.postDelayed(dsRunnable, 60000) + doDs() } /** * 定时 */ + @Synchronized private fun doDs() { - handler.removeCallbacks(dsRunnable) - if (!pause) { - if (timeMinute >= 0) { - timeMinute-- - } - if (timeMinute == 0) { - ReadAloud.stop(this) - } - } postEvent(EventBus.TTS_DS, timeMinute) upNotification() - handler.postDelayed(dsRunnable, 60000) + dsJob?.cancel() + dsJob = launch { + while (isActive) { + delay(60000) + if (isActive) { + if (!pause) { + if (timeMinute >= 0) { + timeMinute-- + } + if (timeMinute == 0) { + ReadAloud.stop(this@BaseReadAloudService) + } + } + postEvent(EventBus.TTS_DS, timeMinute) + upNotification() + } + } + } } /** diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 0e75eb04e..18788fa4a 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -10,8 +10,10 @@ import io.legado.app.model.ReadBook import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.service.help.ReadAloud import io.legado.app.utils.* +import kotlinx.coroutines.delay import kotlinx.coroutines.ensureActive import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import java.io.File import java.io.FileDescriptor import java.io.FileInputStream @@ -238,7 +240,8 @@ class HttpReadAloudService : BaseReadAloudService(), if (what == -38 && extra == 0) { return true } - handler.postDelayed({ + launch { + delay(100) readAloudNumber += contentList[nowSpeak].length + 1 if (nowSpeak < contentList.lastIndex) { nowSpeak++ @@ -246,7 +249,7 @@ class HttpReadAloudService : BaseReadAloudService(), } else { nextChapter() } - }, 50) + } return true } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 7025b6442..5dbaa9de3 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -5,8 +5,6 @@ import android.app.Activity import android.content.Intent import android.content.res.Configuration import android.os.Bundle -import android.os.Handler -import android.os.Looper import android.view.* import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import androidx.activity.result.contract.ActivityResultContracts @@ -53,7 +51,9 @@ import io.legado.app.ui.replace.edit.ReplaceEditActivity import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.utils.* import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Job import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch class ReadBookActivity : ReadBookBaseActivity(), @@ -109,15 +109,9 @@ class ReadBookActivity : ReadBookBaseActivity(), override val isInitFinish: Boolean get() = viewModel.isInitFinish override val isScroll: Boolean get() = binding.readView.isScroll - private val mHandler = Handler(Looper.getMainLooper()) - private val keepScreenRunnable = Runnable { keepScreenOn(false) } - private val autoPageRunnable = Runnable { autoPagePlus() } - private val backupRunnable = Runnable { - if (!BuildConfig.DEBUG) { - ReadBook.uploadProgress() - Backup.autoBack(this) - } - } + private var keepScreenJon: Job? = null + private var autoPageJob: Job? = null + private var backupJob: Job? = null override var autoPageProgress = 0 override var isAutoPage = false private var screenTimeOut: Long = 0 @@ -169,7 +163,7 @@ class ReadBookActivity : ReadBookBaseActivity(), override fun onPause() { super.onPause() autoPageStop() - mHandler.removeCallbacks(backupRunnable) + backupJob?.cancel() ReadBook.saveRead() timeBatteryReceiver?.let { unregisterReceiver(it) @@ -629,7 +623,7 @@ class ReadBookActivity : ReadBookBaseActivity(), launch { autoPageProgress = 0 binding.readMenu.setSeekPage(ReadBook.durPageIndex()) - mHandler.postDelayed(backupRunnable, 600000) + startBackupJob() } } @@ -692,38 +686,43 @@ class ReadBookActivity : ReadBookBaseActivity(), override fun autoPageStop() { if (isAutoPage) { isAutoPage = false - mHandler.removeCallbacks(autoPageRunnable) + autoPageJob?.cancel() + binding.readView.invalidate() binding.readMenu.setAutoPage(false) upScreenTimeOut() } } private fun autoPagePlus() { - var delayMillis = ReadBookConfig.autoReadSpeed * 1000L / binding.readView.height - var scrollOffset = 1 - if (delayMillis < 20) { - var delayInt = delayMillis.toInt() - if (delayInt == 0) delayInt = 1 - scrollOffset = 20 / delayInt - delayMillis = 20 - } - mHandler.removeCallbacks(autoPageRunnable) - if (!menuLayoutIsVisible) { - if (binding.readView.isScroll) { - binding.readView.curPage.scroll(-scrollOffset) - } else { - autoPageProgress += scrollOffset - if (autoPageProgress >= binding.readView.height) { - autoPageProgress = 0 - if (!binding.readView.fillPage(PageDirection.NEXT)) { - autoPageStop() + autoPageJob?.cancel() + autoPageJob = launch { + while (isActive) { + var delayMillis = ReadBookConfig.autoReadSpeed * 1000L / binding.readView.height + var scrollOffset = 1 + if (delayMillis < 20) { + var delayInt = delayMillis.toInt() + if (delayInt == 0) delayInt = 1 + scrollOffset = 20 / delayInt + delayMillis = 20 + } + delay(delayMillis) + if (!menuLayoutIsVisible && isActive) { + if (binding.readView.isScroll) { + binding.readView.curPage.scroll(-scrollOffset) + } else { + autoPageProgress += scrollOffset + if (autoPageProgress >= binding.readView.height) { + autoPageProgress = 0 + if (!binding.readView.fillPage(PageDirection.NEXT)) { + autoPageStop() + } + } else { + binding.readView.invalidate() + } } - } else { - binding.readView.invalidate() } } } - mHandler.postDelayed(autoPageRunnable, delayMillis) } override fun openSourceEditActivity() { @@ -878,6 +877,13 @@ class ReadBookActivity : ReadBookBaseActivity(), } } + private fun startBackupJob() { + backupJob?.cancel() + backupJob = launch { + delay(120000) + } + } + override fun finish() { ReadBook.book?.let { if (!ReadBook.inBookshelf) { @@ -897,7 +903,6 @@ class ReadBookActivity : ReadBookBaseActivity(), override fun onDestroy() { super.onDestroy() - mHandler.removeCallbacks(keepScreenRunnable) textActionMenu.dismiss() binding.readView.onDestroy() ReadBook.msg = null @@ -975,17 +980,20 @@ class ReadBookActivity : ReadBookBaseActivity(), * 重置黑屏时间 */ override fun screenOffTimerStart() { - if (screenTimeOut < 0) { - keepScreenOn(true) - return - } - val t = screenTimeOut - sysScreenOffTime - if (t > 0) { - mHandler.removeCallbacks(keepScreenRunnable) - keepScreenOn(true) - mHandler.postDelayed(keepScreenRunnable, screenTimeOut) - } else { - keepScreenOn(false) + keepScreenJon?.cancel() + keepScreenJon = launch { + if (screenTimeOut < 0) { + keepScreenOn(true) + return@launch + } + val t = screenTimeOut - sysScreenOffTime + if (t > 0) { + keepScreenOn(true) + delay(screenTimeOut) + keepScreenOn(false) + } else { + keepScreenOn(false) + } } } } \ No newline at end of file