pull/1319/head
gedoor 3 years ago
parent a9e88cac04
commit 10c10b1229
  1. 120
      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,35 +52,68 @@ 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)
}
}
}
@Synchronized
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()
}
} }
for (i in 0 until threadCount) {
if (usePoolCount < threadCount) { private fun startUpTocJob() {
usePoolCount++ upTocJob = viewModelScope.launch(upTocPool) {
while (isActive) {
when {
waitUpTocBooks.isEmpty() -> {
upTocJob?.cancel()
upTocJob = null
}
onUpTocBooks.size < threadCount -> {
updateToc() updateToc()
} }
else -> {
delay(500)
}
}
} }
} }
} }
@Synchronized @Synchronized
private fun updateToc() { private fun updateToc() {
var update = false val bookUrl = waitUpTocBooks.firstOrNull() ?: return
bookMap.forEach { bookEntry -> if (onUpTocBooks.contains(bookUrl)) {
if (!updateList.contains(bookEntry.key)) { waitUpTocBooks.remove(bookUrl)
update = true return
val book = bookEntry.value }
synchronized(this) { val book = appDb.bookDao.getBook(bookUrl)
updateList.add(book.bookUrl) if (book == null) {
postEvent(EventBus.UP_BOOKSHELF, book.bookUrl) waitUpTocBooks.remove(bookUrl)
return
} }
appDb.bookSourceDao.getBookSource(book.origin)?.let { bookSource -> 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) { execute(context = upTocPool) {
if (book.tocUrl.isBlank()) { if (book.tocUrl.isBlank()) {
WebBook.getBookInfoAwait(this, bookSource, book) WebBook.getBookInfoAwait(this, source, book)
} }
val toc = WebBook.getChapterListAwait(this, bookSource, book) val toc = WebBook.getChapterListAwait(this, source, book)
appDb.bookDao.update(book) appDb.bookDao.update(book)
appDb.bookChapterDao.delByBook(book.bookUrl) appDb.bookChapterDao.delByBook(book.bookUrl)
appDb.bookChapterDao.insert(*toc.toTypedArray()) appDb.bookChapterDao.insert(*toc.toTypedArray())
@ -90,28 +121,29 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
}.onError(upTocPool) { }.onError(upTocPool) {
AppLog.addLog("${book.name} 更新目录失败\n${it.localizedMessage}", it) AppLog.addLog("${book.name} 更新目录失败\n${it.localizedMessage}", it)
it.printOnDebug() it.printOnDebug()
}.onCancel(upTocPool) {
upTocCancel(book.bookUrl)
}.onFinally(upTocPool) { }.onFinally(upTocPool) {
synchronized(this) { upTocFinally(book.bookUrl)
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 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