Merge pull request #2099 from 821938089/opt-cache-manager

优化章节缓存
pull/2102/head
kunfei 2 years ago committed by GitHub
commit 37a057b2c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt
  2. 30
      app/src/main/java/io/legado/app/model/CacheBook.kt
  3. 7
      app/src/main/java/io/legado/app/service/CacheBookService.kt
  4. 1
      app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt
  5. 4
      app/src/main/java/io/legado/app/ui/book/cache/CacheAdapter.kt
  6. 13
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt

@ -40,6 +40,8 @@ class Coroutine<T>(
private var timeMillis: Long? = null
private var errorReturn: Result<T>? = null
private var isCancelCalled = false
val isCancelled: Boolean
get() = job.isCancelled
@ -115,6 +117,7 @@ class Coroutine<T>(
//取消当前任务
fun cancel(cause: CancellationException? = null) {
isCancelCalled = true
job.cancel(cause)
cancel?.let {
MainScope().launch {
@ -146,6 +149,7 @@ class Coroutine<T>(
success?.let { dispatchCallback(this, value, it) }
} catch (e: Throwable) {
e.printOnDebug()
if (e is CancellationException && !isCancelCalled) this@Coroutine.cancel()
if (e is CancellationException && e !is TimeoutCancellationException) {
return@launch
}

@ -135,6 +135,8 @@ object CacheBook {
private val onDownloadSet = linkedSetOf<Int>()
private val successDownloadSet = linkedSetOf<Int>()
private val errorDownloadMap = hashMapOf<Int, Int>()
private var isStopped = false
private var waitingRetry = false
val waitCount get() = waitDownloadSet.size
val onDownloadCount get() = onDownloadSet.size
@ -146,13 +148,20 @@ object CacheBook {
return waitDownloadSet.size > 0 || onDownloadSet.size > 0
}
@Synchronized
fun isStop(): Boolean {
return isStopped || (!isRun() && !waitingRetry)
}
@Synchronized
fun stop() {
waitDownloadSet.clear()
isStopped = true
}
@Synchronized
fun addDownload(start: Int, end: Int) {
isStopped = false
for (i in start..end) {
if (!onDownloadSet.contains(i)) {
waitDownloadSet.add(i)
@ -168,13 +177,18 @@ object CacheBook {
}
@Synchronized
private fun onError(index: Int, error: Throwable, chapterTitle: String) {
private fun onPreError(index: Int, error: Throwable) {
waitingRetry = true
if (error !is ConcurrentException) {
errorDownloadMap[index] = (errorDownloadMap[index] ?: 0) + 1
}
onDownloadSet.remove(index)
}
@Synchronized
private fun onPostError(index: Int, error: Throwable, chapterTitle: String) {
//重试3次
if ((errorDownloadMap[index] ?: 0) < 3) {
if ((errorDownloadMap[index] ?: 0) < 3 && !isStopped) {
waitDownloadSet.add(index)
} else {
AppLog.put(
@ -182,12 +196,19 @@ object CacheBook {
error
)
}
waitingRetry = false
}
@Synchronized
private fun onError(index: Int, error: Throwable, chapterTitle: String) {
onPreError(index, error)
onPostError(index, error, chapterTitle)
}
@Synchronized
private fun onCancel(index: Int) {
onDownloadSet.remove(index)
waitDownloadSet.add(index)
if (!isStopped) waitDownloadSet.add(index)
}
@Synchronized
@ -234,9 +255,10 @@ object CacheBook {
onSuccess(chapterIndex)
downloadFinish(chapter, content)
}.onError {
onPreError(chapterIndex, it)
//出现错误等待一秒后重新加入待下载列表
delay(1000)
onError(chapterIndex, it, chapter.title)
onPostError(chapterIndex, it, chapter.title)
downloadFinish(chapter, "获取正文失败\n${it.localizedMessage}")
}.onCancel {
onCancel(chapterIndex)

@ -74,6 +74,7 @@ class CacheBookService : BaseService() {
override fun onDestroy() {
isRun = false
cachePool.close()
CacheBook.cacheBookMap.forEach { it.value.stop() }
CacheBook.cacheBookMap.clear()
super.onDestroy()
postEvent(EventBus.UP_DOWNLOAD, "")
@ -84,6 +85,7 @@ class CacheBookService : BaseService() {
execute {
val cacheBook = CacheBook.getOrCreate(bookUrl) ?: return@execute
cacheBook.addDownload(start, end)
postEvent(EventBus.UP_DOWNLOAD, "")
upNotification(CacheBook.downloadSummary)
if (downloadJob == null) {
download()
@ -93,6 +95,11 @@ class CacheBookService : BaseService() {
private fun removeDownload(bookUrl: String?) {
CacheBook.cacheBookMap[bookUrl]?.stop()
postEvent(EventBus.UP_DOWNLOAD, "")
if (downloadJob == null && CacheBook.isRun) {
download()
return
}
if (CacheBook.cacheBookMap.isEmpty()) {
stopSelf()
}

@ -237,6 +237,7 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
observeEvent<BookChapter>(EventBus.SAVE_CONTENT) {
adapter.cacheChapters[it.bookUrl]?.add(it.url)
}
postEventDelay(EventBus.UP_DOWNLOAD, "", 100)
}
override fun export(position: Int) {

@ -67,7 +67,7 @@ class CacheAdapter(context: Context, private val callBack: CallBack) :
ivDownload.setOnClickListener {
getItem(holder.layoutPosition)?.let { book ->
CacheBook.cacheBookMap[book.bookUrl]?.let {
if (it.isRun()) {
if (!it.isStop()) {
CacheBook.remove(context, book.bookUrl)
} else {
CacheBook.start(context, book, 0, book.totalChapterNum)
@ -89,7 +89,7 @@ class CacheAdapter(context: Context, private val callBack: CallBack) :
} else {
iv.visible()
CacheBook.cacheBookMap[book.bookUrl]?.let {
if (it.isRun()) {
if (!it.isStop()) {
iv.setImageResource(R.drawable.ic_stop_black_24dp)
} else {
iv.setImageResource(R.drawable.ic_play_24dp)

@ -186,13 +186,14 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
private fun cacheBook() {
cacheBookJob?.cancel()
cacheBookJob = viewModelScope.launch(upTocPool) {
while (isActive) {
if (CacheBookService.isRun) {
cacheBookJob?.cancel()
cacheBookJob = null
return@launch
launch {
while (isActive) {
postEvent(EventBus.UP_DOWNLOAD, "")
delay(1000)
}
if (!CacheBook.isRun) {
}
while (isActive) {
if (CacheBookService.isRun || !CacheBook.isRun) {
cacheBookJob?.cancel()
cacheBookJob = null
return@launch

Loading…
Cancel
Save