From de39ddbd13771a806575da440a9450ead13e8564 Mon Sep 17 00:00:00 2001 From: Horis <8674809+821938089@users.noreply.github.com> Date: Tue, 14 Oct 2025 11:30:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/App.kt | 2 + .../io/legado/app/help/DispatchersMonitor.kt | 59 +++++++++++++++++++ .../app/ui/config/OtherConfigFragment.kt | 2 + .../bookshelf/style1/books/BooksFragment.kt | 2 +- 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/help/DispatchersMonitor.kt diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index f408655fb..364f93f96 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -34,6 +34,7 @@ import io.legado.app.help.AppFreezeMonitor import io.legado.app.help.AppWebDav import io.legado.app.help.CrashHandler import io.legado.app.help.DefaultData +import io.legado.app.help.DispatchersMonitor import io.legado.app.help.LifecycleHelp import io.legado.app.help.RuleBigDataHelp import io.legado.app.help.book.BookHelp @@ -89,6 +90,7 @@ class App : Application() { .setLogger(EventLogger()) DefaultData.upVersion() AppFreezeMonitor.init(this@App) + DispatchersMonitor.init() URL.setURLStreamHandlerFactory(ObsoleteUrlFactory(okHttpClient)) launch { installGmsTlsProvider(appCtx) } initRhino() diff --git a/app/src/main/java/io/legado/app/help/DispatchersMonitor.kt b/app/src/main/java/io/legado/app/help/DispatchersMonitor.kt new file mode 100644 index 000000000..49d418760 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/DispatchersMonitor.kt @@ -0,0 +1,59 @@ +package io.legado.app.help + +import io.legado.app.help.config.AppConfig +import io.legado.app.utils.LogUtils +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers.Default +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import kotlinx.coroutines.selects.onTimeout +import kotlinx.coroutines.selects.select +import kotlinx.coroutines.withContext +import java.util.concurrent.Executors + +object DispatchersMonitor { + + private const val TAG = "DispatchersMonitor" + + private val dispatcher by lazy { + Executors.newSingleThreadExecutor { + Thread(it, TAG) + }.asCoroutineDispatcher() + } + + private val scope = CoroutineScope(dispatcher) + + fun init() { + scope.coroutineContext.cancelChildren() + if (!AppConfig.recordLog) { + return + } + monitor(IO) + monitor(Default) + monitor(Main) + } + + @OptIn(ExperimentalCoroutinesApi::class) + private fun monitor(dispatcher: CoroutineDispatcher) { + scope.launch { + while (isActive) select { + launch { + withContext(dispatcher) { + delay(3000) + } + }.onJoin {} + onTimeout(5000) { + LogUtils.d(TAG, "Dispatcher $dispatcher is timed out waiting for for 5000ms.") + } + } + } + } + +} diff --git a/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt index 5482cd38a..7fa758b4f 100644 --- a/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt @@ -16,6 +16,7 @@ import io.legado.app.constant.EventBus import io.legado.app.constant.PreferKey import io.legado.app.databinding.DialogEditTextBinding import io.legado.app.help.AppFreezeMonitor +import io.legado.app.help.DispatchersMonitor import io.legado.app.help.config.AppConfig import io.legado.app.help.config.LocalConfig import io.legado.app.lib.dialogs.alert @@ -189,6 +190,7 @@ class OtherConfigFragment : PreferenceFragment(), LogUtils.logDeviceInfo() LiveEventBus.config().enableLogger(AppConfig.recordLog) AppFreezeMonitor.init(appCtx) + DispatchersMonitor.init() } PreferKey.processText -> sharedPreferences?.let { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt index 34d944450..43372aabe 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt @@ -203,7 +203,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books), if (!AppConfig.showLastUpdateTime || bookshelfLayout != 0) { return } - upLastUpdateTimeJob = lifecycleScope.launch { + upLastUpdateTimeJob = viewLifecycleOwner.lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.RESUMED) { while (isActive) { booksAdapter.upLastUpdateTime()