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

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

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

Loading…
Cancel
Save