feat: 优化下载

pull/262/head
gedoor 5 years ago
parent cdbb2cabe4
commit 09a405647a
  1. 153
      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<String, Book>()
private val webBookMap = hashMapOf<String, WebBook>()
private val downloadMap = hashMapOf<String, LinkedHashSet<BookChapter>>()
private val downloadCount = hashMapOf<String, DownloadCount>()
private val finalMap = hashMapOf<String, LinkedHashSet<BookChapter>>()
private val downloadingList = arrayListOf<String>()
@Volatile
private var downloadingCount = 0
private var notificationContent = "正在启动下载"
private val notificationBuilder by lazy {
@ -78,92 +86,136 @@ 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<BookChapter>().apply {
downloadMap[bookUrl] = this
}
App.db.bookChapterDao().getChapterList(bookUrl, start, end).let {
chapterMap.addAll(it)
if (it.isNotEmpty()) {
val chapters = linkedSetOf<BookChapter>()
chapters.addAll(it)
downloadMap[bookUrl] = chapters
}
}
for (i in 0 until threadCount) {
if (downloadingCount < threadCount) {
download()
}
}
}
}
private fun removeDownload(bookUrl: String?) {
downloadMap.remove(bookUrl)
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 ->
++downloadingCount
tasks.add(Coroutine.async(this, context = searchPool) {
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)) {
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,
chapter,
bookChapter,
scope = this,
context = searchPool
).onSuccess(IO) { content ->
downloadCount[entry.key]?.increaseSuccess()
BookHelp.saveContent(book, chapter, content)
}
.onFinally(IO) {
downloadCount[book.bookUrl]?.increaseSuccess()
BookHelp.saveContent(book, bookChapter, content)
}.onFinally(IO) {
synchronized(this@DownloadService) {
downloadCount[entry.key]?.increaseFinished()
downloadCount[entry.key]?.let { updateNotification(it, entry.value.size, chapter.title) }
downloadCount[book.bookUrl]?.increaseFinished()
downloadCount[book.bookUrl]?.let {
updateNotification(
it,
downloadMap[book.bookUrl]?.size,
bookChapter.title
)
}
val chapterMap =
finalMap[book.bookUrl]
?: linkedSetOf<BookChapter>().apply {
finalMap[book.bookUrl] = this
}
chapterMap.add(chapter)
if (chapterMap.size == entry.value.size) {
chapterMap.add(bookChapter)
if (chapterMap.size == downloadMap[book.bookUrl]?.size) {
downloadMap.remove(book.bookUrl)
finalMap.remove(book.bookUrl)
downloadCount.remove(entry.key)
downloadCount.remove(book.bookUrl)
}
}
}
} else{
postDownloading(true)
} else {
//无需下载的,设置为增加成功
downloadCount[entry.key]?.increaseSuccess()
downloadCount[entry.key]?.increaseFinished()
}
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"
}
/**
* 更新通知
*/

Loading…
Cancel
Save