pull/1319/head
gedoor 3 years ago
parent a9e88cac04
commit 10c10b1229
  1. 148
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt
  2. 2
      app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt
  3. 2
      app/src/main/java/io/legado/app/ui/main/bookshelf/style2/BookshelfFragment2.kt

@ -1,6 +1,7 @@
package io.legado.app.ui.main
import android.app.Application
import androidx.lifecycle.viewModelScope
import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppConst
import io.legado.app.constant.AppLog
@ -16,8 +17,7 @@ import io.legado.app.model.CacheBook
import io.legado.app.model.webBook.WebBook
import io.legado.app.utils.postEvent
import io.legado.app.utils.printOnDebug
import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.*
import java.util.concurrent.CopyOnWriteArraySet
import java.util.concurrent.Executors
import kotlin.math.min
@ -26,11 +26,9 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
private var threadCount = AppConfig.threadCount
private var upTocPool =
Executors.newFixedThreadPool(min(threadCount, AppConst.MAX_THREAD)).asCoroutineDispatcher()
val updateList = CopyOnWriteArraySet<String>()
private val bookMap = ConcurrentHashMap<String, Book>()
@Volatile
private var usePoolCount = 0
val onUpTocBooks = CopyOnWriteArraySet<String>()
private val waitUpTocBooks = arrayListOf<String>()
private var upTocJob: Job? = null
override fun onCleared() {
super.onCleared()
@ -46,7 +44,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
fun upAllBookToc() {
execute {
upToc(appDb.bookDao.hasUpdateBooks)
addToWaitUp(appDb.bookDao.hasUpdateBooks)
}
}
@ -54,64 +52,98 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
execute(context = upTocPool) {
books.filter {
it.origin != BookType.local && it.canUpdate
}.forEach {
bookMap[it.bookUrl] = it
}
for (i in 0 until threadCount) {
if (usePoolCount < threadCount) {
usePoolCount++
updateToc()
}
}.let {
addToWaitUp(it)
}
}
}
@Synchronized
private fun updateToc() {
var update = false
bookMap.forEach { bookEntry ->
if (!updateList.contains(bookEntry.key)) {
update = true
val book = bookEntry.value
synchronized(this) {
updateList.add(book.bookUrl)
postEvent(EventBus.UP_BOOKSHELF, book.bookUrl)
}
appDb.bookSourceDao.getBookSource(book.origin)?.let { bookSource ->
execute(context = upTocPool) {
if (book.tocUrl.isBlank()) {
WebBook.getBookInfoAwait(this, bookSource, book)
}
val toc = WebBook.getChapterListAwait(this, bookSource, book)
appDb.bookDao.update(book)
appDb.bookChapterDao.delByBook(book.bookUrl)
appDb.bookChapterDao.insert(*toc.toTypedArray())
cacheBook(book)
}.onError(upTocPool) {
AppLog.addLog("${book.name} 更新目录失败\n${it.localizedMessage}", it)
it.printOnDebug()
}.onFinally(upTocPool) {
synchronized(this) {
bookMap.remove(bookEntry.key)
updateList.remove(book.bookUrl)
postEvent(EventBus.UP_BOOKSHELF, book.bookUrl)
upNext()
}
private fun addToWaitUp(books: List<Book>) {
books.forEach { book ->
if (!waitUpTocBooks.contains(book.bookUrl) && !onUpTocBooks.contains(book.bookUrl)) {
waitUpTocBooks.add(book.bookUrl)
}
}
if (upTocJob == null) {
startUpTocJob()
}
}
private fun startUpTocJob() {
upTocJob = viewModelScope.launch(upTocPool) {
while (isActive) {
when {
waitUpTocBooks.isEmpty() -> {
upTocJob?.cancel()
upTocJob = null
}
onUpTocBooks.size < threadCount -> {
updateToc()
}
else -> {
delay(500)
}
} ?: synchronized(this) {
bookMap.remove(bookEntry.key)
updateList.remove(book.bookUrl)
postEvent(EventBus.UP_BOOKSHELF, book.bookUrl)
upNext()
}
return
}
}
if (!update) {
usePoolCount--
}
@Synchronized
private fun updateToc() {
val bookUrl = waitUpTocBooks.firstOrNull() ?: return
if (onUpTocBooks.contains(bookUrl)) {
waitUpTocBooks.remove(bookUrl)
return
}
val book = appDb.bookDao.getBook(bookUrl)
if (book == null) {
waitUpTocBooks.remove(bookUrl)
return
}
val source = appDb.bookSourceDao.getBookSource(book.origin)
if (source == null) {
waitUpTocBooks.remove(book.bookUrl)
return
}
waitUpTocBooks.remove(book.bookUrl)
onUpTocBooks.add(book.bookUrl)
postEvent(EventBus.UP_BOOKSHELF, book.bookUrl)
execute(context = upTocPool) {
if (book.tocUrl.isBlank()) {
WebBook.getBookInfoAwait(this, source, book)
}
val toc = WebBook.getChapterListAwait(this, source, book)
appDb.bookDao.update(book)
appDb.bookChapterDao.delByBook(book.bookUrl)
appDb.bookChapterDao.insert(*toc.toTypedArray())
cacheBook(book)
}.onError(upTocPool) {
AppLog.addLog("${book.name} 更新目录失败\n${it.localizedMessage}", it)
it.printOnDebug()
}.onCancel(upTocPool) {
upTocCancel(book.bookUrl)
}.onFinally(upTocPool) {
upTocFinally(book.bookUrl)
}
}
@Synchronized
private fun upTocCancel(bookUrl: String) {
onUpTocBooks.remove(bookUrl)
waitUpTocBooks.add(bookUrl)
}
@Synchronized
private fun upTocFinally(bookUrl: String) {
waitUpTocBooks.remove(bookUrl)
onUpTocBooks.remove(bookUrl)
postEvent(EventBus.UP_BOOKSHELF, bookUrl)
}
/**
* 缓存书籍
*/
private fun cacheBook(book: Book) {
val endIndex = min(
book.totalChapterNum - 1,
@ -128,14 +160,6 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
}
private fun upNext() {
if (bookMap.size > updateList.size) {
updateToc()
} else {
usePoolCount--
}
}
fun postLoad() {
execute {
if (appDb.httpTTSDao.count == 0) {

@ -163,7 +163,7 @@ class BooksFragment : BaseFragment(R.layout.fragment_books),
}
override fun isUpdate(bookUrl: String): Boolean {
return bookUrl in activityViewModel.updateList
return bookUrl in activityViewModel.onUpTocBooks
}
@SuppressLint("NotifyDataSetChanged")

@ -200,7 +200,7 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
}
override fun isUpdate(bookUrl: String): Boolean {
return bookUrl in activityViewModel.updateList
return bookUrl in activityViewModel.onUpTocBooks
}
override fun getItemCount(): Int {

Loading…
Cancel
Save