优化下载

pull/1298/head
gedoor 3 years ago
parent 4089b59e15
commit 6205e00e55
  1. 137
      app/src/main/java/io/legado/app/model/CacheBook.kt
  2. 2
      app/src/main/java/io/legado/app/service/CacheBookService.kt

@ -17,7 +17,6 @@ import kotlinx.coroutines.CoroutineScope
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class CacheBook(val bookSource: BookSource, val book: Book) { class CacheBook(val bookSource: BookSource, val book: Book) {
@ -117,63 +116,79 @@ class CacheBook(val bookSource: BookSource, val book: Book) {
} }
val waitDownloadSet = CopyOnWriteArraySet<Int>() val waitDownloadSet = hashSetOf<Int>()
val onDownloadSet = CopyOnWriteArraySet<Int>() val onDownloadSet = hashSetOf<Int>()
val successDownloadSet = CopyOnWriteArraySet<Int>() val successDownloadSet = hashSetOf<Int>()
fun addDownload(start: Int, end: Int) { fun addDownload(start: Int, end: Int) {
for (i in start..end) { synchronized(this) {
waitDownloadSet.add(i) for (i in start..end) {
waitDownloadSet.add(i)
}
} }
} }
fun isRun(): Boolean { fun isRun(): Boolean {
return waitDownloadSet.size > 0 || onDownloadSet.size > 0 return synchronized(this) {
waitDownloadSet.size > 0 || onDownloadSet.size > 0
}
} }
@Synchronized private fun onSuccess(index: Int) {
fun download(scope: CoroutineScope, context: CoroutineContext): Boolean { synchronized(this) {
val chapterIndex = waitDownloadSet.firstOrNull() ?: return false onDownloadSet.remove(index)
if (onDownloadSet.contains(chapterIndex)) { successDownloadSet.add(index)
waitDownloadSet.remove(chapterIndex)
return download(scope, context)
} }
val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, chapterIndex) ?: let { }
waitDownloadSet.remove(chapterIndex)
return download(scope, context) private fun onErrorOrCancel(index: Int) {
synchronized(this) {
onDownloadSet.remove(index)
waitDownloadSet.add(index)
} }
if (BookHelp.hasContent(book, chapter)) { }
fun download(scope: CoroutineScope, context: CoroutineContext): Boolean {
synchronized(this) {
val chapterIndex = waitDownloadSet.firstOrNull() ?: return false
if (onDownloadSet.contains(chapterIndex)) {
waitDownloadSet.remove(chapterIndex)
return download(scope, context)
}
val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, chapterIndex) ?: let {
waitDownloadSet.remove(chapterIndex)
return download(scope, context)
}
if (BookHelp.hasContent(book, chapter)) {
waitDownloadSet.remove(chapterIndex)
return download(scope, context)
}
waitDownloadSet.remove(chapterIndex) waitDownloadSet.remove(chapterIndex)
return download(scope, context) onDownloadSet.add(chapterIndex)
} WebBook.getContent(
waitDownloadSet.remove(chapterIndex) scope,
onDownloadSet.add(chapterIndex) bookSource,
WebBook.getContent( book,
scope, chapter,
bookSource, context = context
book, ).onSuccess { content ->
chapter, onSuccess(chapterIndex)
context = context addLog("${book.name}-${chapter.title} getContentSuccess")
).onSuccess { content -> downloadFinish(chapter, content.ifBlank { "No content" })
onDownloadSet.remove(chapterIndex) }.onError {
successDownloadSet.add(chapterIndex) onErrorOrCancel(chapterIndex)
addLog("${book.name}-${chapter.title} getContentSuccess") print(it.localizedMessage)
downloadFinish(chapter, content.ifBlank { "No content" }) addLog("${book.name}-${chapter.title} getContentError${it.localizedMessage}")
}.onError { downloadFinish(chapter, it.localizedMessage ?: "download error")
onDownloadSet.remove(chapterIndex) }.onCancel {
waitDownloadSet.add(chapterIndex) onErrorOrCancel(chapterIndex)
print(it.localizedMessage) }.onFinally {
addLog("${book.name}-${chapter.title} getContentError${it.localizedMessage}") if (waitDownloadSet.isEmpty() && onDownloadSet.isEmpty()) {
downloadFinish(chapter, it.localizedMessage ?: "download error") postEvent(EventBus.UP_DOWNLOAD, "")
}.onCancel { }
onDownloadSet.remove(chapterIndex)
waitDownloadSet.add(chapterIndex)
}.onFinally {
if (waitDownloadSet.isEmpty() && onDownloadSet.isEmpty()) {
postEvent(EventBus.UP_DOWNLOAD, "")
} }
return true
} }
return true
} }
@Synchronized @Synchronized
@ -182,19 +197,27 @@ class CacheBook(val bookSource: BookSource, val book: Book) {
chapter: BookChapter, chapter: BookChapter,
resetPageOffset: Boolean = false resetPageOffset: Boolean = false
) { ) {
if (onDownloadSet.contains(chapter.index)) { synchronized(this) {
return if (onDownloadSet.contains(chapter.index)) {
} return
onDownloadSet.add(chapter.index)
WebBook.getContent(scope, bookSource, book, chapter)
.onSuccess { content ->
downloadFinish(chapter, content.ifBlank { "No content" }, resetPageOffset)
}.onError {
downloadFinish(chapter, it.localizedMessage ?: "download error", resetPageOffset)
}.onFinally {
onDownloadSet.remove(chapter.index)
ReadBook.removeLoading(chapter.index)
} }
onDownloadSet.add(chapter.index)
WebBook.getContent(scope, bookSource, book, chapter)
.onSuccess { content ->
downloadFinish(chapter, content.ifBlank { "No content" }, resetPageOffset)
}.onError {
downloadFinish(
chapter,
it.localizedMessage ?: "download error",
resetPageOffset
)
}.onFinally {
synchronized(this) {
onDownloadSet.remove(chapter.index)
}
ReadBook.removeLoading(chapter.index)
}
}
} }
private fun downloadFinish( private fun downloadFinish(

@ -92,7 +92,7 @@ class CacheBookService : BaseService() {
while (isActive) { while (isActive) {
CacheBook.cacheBookMap.forEach { CacheBook.cacheBookMap.forEach {
while (CacheBook.onDownloadCount > threadCount) { while (CacheBook.onDownloadCount > threadCount) {
delay(50) delay(100)
} }
it.value.download(this, cachePool) it.value.download(this, cachePool)
} }

Loading…
Cancel
Save