From 09a405647af5230e4e8650a63b31bba48db6306f Mon Sep 17 00:00:00 2001 From: gedoor Date: Sat, 27 Jun 2020 11:54:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/service/DownloadService.kt | 185 ++++++++++++------ 1 file changed, 123 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index bf6b90629..845f99fc0 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -9,6 +9,7 @@ import io.legado.app.base.BaseService import io.legado.app.constant.AppConst import io.legado.app.constant.EventBus import io.legado.app.constant.IntentAction +import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.AppConfig import io.legado.app.help.BookHelp @@ -24,14 +25,21 @@ import org.jetbrains.anko.toast import java.util.concurrent.Executors class DownloadService : BaseService() { + private val threadCount = AppConfig.threadCount private var searchPool = - Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher() + Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher() private var tasks = CompositeCoroutine() private val handler = Handler() private var runnable: Runnable = Runnable { upDownload() } + private val bookMap = hashMapOf() + private val webBookMap = hashMapOf() private val downloadMap = hashMapOf>() private val downloadCount = hashMapOf() private val finalMap = hashMapOf>() + private val downloadingList = arrayListOf() + + @Volatile + private var downloadingCount = 0 private var notificationContent = "正在启动下载" private val notificationBuilder by lazy { @@ -78,20 +86,50 @@ class DownloadService : BaseService() { postEvent(EventBus.UP_DOWNLOAD, downloadMap) } + private fun getBook(bookUrl: String): Book? { + var book = bookMap[bookUrl] + if (book == null) { + book = App.db.bookDao().getBook(bookUrl) + } + if (book == null) { + removeDownload(bookUrl) + } + return book + } + + private fun getWebBook(bookUrl: String, origin: String): WebBook? { + var webBook = webBookMap[origin] + if (webBook == null) { + App.db.bookSourceDao().getBookSource(origin)?.let { + webBook = WebBook(it) + } + } + if (webBook == null) { + removeDownload(bookUrl) + } + return webBook + } + private fun addDownloadData(bookUrl: String?, start: Int, end: Int) { bookUrl ?: return if (downloadMap.containsKey(bookUrl)) { toast("该书已在下载列表") return } + downloadCount[bookUrl] = DownloadCount() execute { - val chapterMap = downloadMap[bookUrl] ?: linkedSetOf().apply { - downloadMap[bookUrl] = this - } App.db.bookChapterDao().getChapterList(bookUrl, start, end).let { - chapterMap.addAll(it) + if (it.isNotEmpty()) { + val chapters = linkedSetOf() + chapters.addAll(it) + downloadMap[bookUrl] = chapters + } + } + for (i in 0 until threadCount) { + if (downloadingCount < threadCount) { + download() + } } - download() } } @@ -100,70 +138,84 @@ class DownloadService : BaseService() { finalMap.remove(bookUrl) } - private fun updateNotification(downloadCount:DownloadCount, totalCount: Int, content: String){ - notificationContent = - "进度:${downloadCount.downloadFinishedCount}/$totalCount,成功:${downloadCount.successCount},$content" - } - private fun download() { - val task = Coroutine.async(this, context = searchPool) { - downloadMap.forEach { entry -> - if (!isActive) return@async - if (!finalMap.containsKey(entry.key)) { - val book = App.db.bookDao().getBook(entry.key) ?: return@async - val bookSource = - App.db.bookSourceDao().getBookSource(book.origin) ?: return@async - val webBook = WebBook(bookSource) - - downloadCount[entry.key] = DownloadCount() - - entry.value.forEach { chapter -> - if (!isActive) return@async - if (downloadMap.containsKey(book.bookUrl)) { - if (!BookHelp.hasContent(book, chapter)) { - webBook.getContent( - book, - chapter, - scope = this, - context = searchPool - ).onSuccess(IO) { content -> - downloadCount[entry.key]?.increaseSuccess() - BookHelp.saveContent(book, chapter, content) - } - .onFinally(IO) { - synchronized(this@DownloadService) { - downloadCount[entry.key]?.increaseFinished() - downloadCount[entry.key]?.let { updateNotification(it, entry.value.size, chapter.title) } - val chapterMap = - finalMap[book.bookUrl] - ?: linkedSetOf().apply { - finalMap[book.bookUrl] = this - } - chapterMap.add(chapter) - if (chapterMap.size == entry.value.size) { - downloadMap.remove(book.bookUrl) - finalMap.remove(book.bookUrl) - downloadCount.remove(entry.key) - } - } + ++downloadingCount + tasks.add(Coroutine.async(this, context = searchPool) { + if (!isActive) return@async + val bookChapter: BookChapter? = synchronized(this@DownloadService) { + downloadMap.forEach { + it.value.forEach { chapter -> + if (!downloadingList.contains(chapter.url)) { + downloadingList.add(chapter.url) + return@synchronized chapter + } + } + } + return@synchronized null + } + if (bookChapter == null) { + postDownloading(false) + } else { + val book = getBook(bookChapter.bookUrl) + if (book == null) { + postDownloading(true) + return@async + } + val webBook = getWebBook(bookChapter.bookUrl, book.origin) + if (webBook == null) { + postDownloading(true) + return@async + } + if (!BookHelp.hasContent(book, bookChapter)) { + webBook.getContent( + book, + bookChapter, + scope = this, + context = searchPool + ).onSuccess(IO) { content -> + downloadCount[book.bookUrl]?.increaseSuccess() + BookHelp.saveContent(book, bookChapter, content) + }.onFinally(IO) { + synchronized(this@DownloadService) { + downloadCount[book.bookUrl]?.increaseFinished() + downloadCount[book.bookUrl]?.let { + updateNotification( + it, + downloadMap[book.bookUrl]?.size, + bookChapter.title + ) + } + val chapterMap = + finalMap[book.bookUrl] + ?: linkedSetOf().apply { + finalMap[book.bookUrl] = this } - } else{ - //无需下载的,设置为增加成功 - downloadCount[entry.key]?.increaseSuccess() - downloadCount[entry.key]?.increaseFinished() + chapterMap.add(bookChapter) + if (chapterMap.size == downloadMap[book.bookUrl]?.size) { + downloadMap.remove(book.bookUrl) + finalMap.remove(book.bookUrl) + downloadCount.remove(book.bookUrl) } } } + postDownloading(true) + } else { + //无需下载的,设置为增加成功 + downloadCount[book.bookUrl]?.increaseSuccess() + downloadCount[book.bookUrl]?.increaseFinished() + postDownloading(true) } - } - } + }) + } - tasks.add(task) - task.invokeOnCompletion { - tasks.remove(task) - if (tasks.isEmpty) { - stopSelf() + private fun postDownloading(hasChapter: Boolean) { + --downloadingCount + if (hasChapter) { + download() + } else { + if (downloadingCount < 1) { + stopDownload() } } } @@ -180,6 +232,15 @@ class DownloadService : BaseService() { handler.postDelayed(runnable, 1000) } + private fun updateNotification( + downloadCount: DownloadCount, + totalCount: Int?, + content: String + ) { + notificationContent = + "进度:${downloadCount.downloadFinishedCount}/$totalCount,成功:${downloadCount.successCount},$content" + } + /** * 更新通知 */