diff --git a/app/src/main/java/io/legado/app/model/ReadBook.kt b/app/src/main/java/io/legado/app/model/ReadBook.kt index c4d0ef32a..0d8b6565b 100644 --- a/app/src/main/java/io/legado/app/model/ReadBook.kt +++ b/app/src/main/java/io/legado/app/model/ReadBook.kt @@ -47,7 +47,9 @@ import kotlinx.coroutines.ensureActive import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Semaphore +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import splitties.init.appCtx import kotlin.math.max @@ -68,6 +70,12 @@ object ReadBook : CoroutineScope by MainScope() { var prevTextChapter: TextChapter? = null var curTextChapter: TextChapter? = null var nextTextChapter: TextChapter? = null + var prevChapterLoadingJob: Coroutine<*>? = null + var curChapterLoadingJob: Coroutine<*>? = null + var nextChapterLoadingJob: Coroutine<*>? = null + var prevChapterLoadingLock = Mutex() + var curChapterLoadingLock = Mutex() + var nextChapterLoadingLock = Mutex() var bookSource: BookSource? = null var msg: String? = null private val loadingChapters = arrayListOf() @@ -675,6 +683,7 @@ object ReadBook : CoroutineScope by MainScope() { /** * 内容加载完成 */ + @Synchronized fun contentLoadFinish( book: Book, chapter: BookChapter, @@ -684,11 +693,17 @@ object ReadBook : CoroutineScope by MainScope() { canceled: Boolean = false, success: (() -> Unit)? = null ) { + removeLoading(chapter.index) if (canceled || chapter.index !in durChapterIndex - 1..durChapterIndex + 1) { - removeLoading(chapter.index) return } - Coroutine.async(start = CoroutineStart.LAZY) { + val offset = chapter.index - durChapterIndex + when (offset) { + 0 -> curChapterLoadingJob?.cancel() + -1 -> prevChapterLoadingJob?.cancel() + 1 -> nextChapterLoadingJob?.cancel() + } + val job = Coroutine.async(this, start = CoroutineStart.LAZY) { val contentProcessor = ContentProcessor.get(book.name, book.origin) val displayTitle = chapter.getDisplayTitle( contentProcessor.getTitleReplaceRules(), @@ -696,12 +711,12 @@ object ReadBook : CoroutineScope by MainScope() { ) val contents = contentProcessor .getContent(book, chapter, content, includeTitle = false) + ensureActive() val textChapter = ChapterProvider.getTextChapterAsync( - this@ReadBook, book, chapter, displayTitle, contents, simulatedChapterSize + this, book, chapter, displayTitle, contents, simulatedChapterSize ) - when (val offset = chapter.index - durChapterIndex) { - 0 -> { - curTextChapter?.cancelLayout() + when (offset) { + 0 -> curChapterLoadingLock.withLock { withContext(Main) { curTextChapter = textChapter } @@ -727,8 +742,7 @@ object ReadBook : CoroutineScope by MainScope() { callBack?.contentLoadFinish() } - -1 -> { - prevTextChapter?.cancelLayout() + -1 -> prevChapterLoadingLock.withLock { withContext(Main) { prevTextChapter = textChapter } @@ -736,8 +750,7 @@ object ReadBook : CoroutineScope by MainScope() { if (upContent) callBack?.upContent(offset, resetPageOffset) } - 1 -> { - nextTextChapter?.cancelLayout() + 1 -> nextChapterLoadingLock.withLock { withContext(Main) { nextTextChapter = textChapter } @@ -759,9 +772,13 @@ object ReadBook : CoroutineScope by MainScope() { appCtx.toastOnUi("ChapterProvider ERROR:\n${it.stackTraceStr}") }.onSuccess { success?.invoke() - }.onFinally { - removeLoading(chapter.index) - }.start() + } + when (offset) { + 0 -> curChapterLoadingJob = job + -1 -> prevChapterLoadingJob = job + 1 -> nextChapterLoadingJob = job + } + job.start() } suspend fun contentLoadFinishAwait( @@ -771,8 +788,8 @@ object ReadBook : CoroutineScope by MainScope() { upContent: Boolean = true, resetPageOffset: Boolean ) { + removeLoading(chapter.index) if (chapter.index !in durChapterIndex - 1..durChapterIndex + 1) { - removeLoading(chapter.index) return } kotlin.runCatching { @@ -843,7 +860,6 @@ object ReadBook : CoroutineScope by MainScope() { AppLog.put("ChapterProvider ERROR", it) appCtx.toastOnUi("ChapterProvider ERROR:\n${it.stackTraceStr}") } - removeLoading(chapter.index) } @Synchronized