优化换源,换封面

pull/348/head 3.20.082919
gedoor 4 years ago
parent fcf7f3720e
commit 4a359c48a8
  1. 104
      app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt
  2. 3
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt

@ -6,24 +6,31 @@ import androidx.lifecycle.MutableLiveData
import io.legado.app.App import io.legado.app.App
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppPattern import io.legado.app.constant.AppPattern
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.SearchBook import io.legado.app.data.entities.SearchBook
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.CompositeCoroutine
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExecutorCoroutineDispatcher
import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.math.min
class ChangeCoverViewModel(application: Application) : BaseViewModel(application) { class ChangeCoverViewModel(application: Application) : BaseViewModel(application) {
private var searchPool = private val threadCount = AppConfig.threadCount
Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher() private var searchPool: ExecutorCoroutineDispatcher? = null
var name: String = "" var name: String = ""
var author: String = "" var author: String = ""
private var task: Coroutine<*>? = null private var tasks = CompositeCoroutine()
private var bookSourceList = arrayListOf<BookSource>()
val searchStateData = MutableLiveData<Boolean>() val searchStateData = MutableLiveData<Boolean>()
val searchBooksLiveData = MutableLiveData<List<SearchBook>>() val searchBooksLiveData = MutableLiveData<List<SearchBook>>()
private val searchBooks = ArrayList<SearchBook>() private val searchBooks = ArrayList<SearchBook>()
@Volatile
private var searchIndex = -1
fun initData(arguments: Bundle?) { fun initData(arguments: Bundle?) {
arguments?.let { bundle -> arguments?.let { bundle ->
bundle.getString("name")?.let { bundle.getString("name")?.let {
@ -35,13 +42,18 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application
} }
} }
private fun initSearchPool() {
searchPool = Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher()
searchIndex = -1
}
fun loadDbSearchBook() { fun loadDbSearchBook() {
execute { execute {
App.db.searchBookDao().getEnableHasCover(name, author).let { App.db.searchBookDao().getEnableHasCover(name, author).let {
searchBooks.addAll(it) searchBooks.addAll(it)
if (it.size <= 1) { if (it.size <= 1) {
searchBooksLiveData.postValue(searchBooks) searchBooksLiveData.postValue(searchBooks)
search() startSearch()
} else { } else {
searchBooksLiveData.postValue(searchBooks) searchBooksLiveData.postValue(searchBooks)
} }
@ -49,50 +61,70 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application
} }
} }
fun search() { private fun startSearch() {
task = execute { execute {
val bookSourceList = App.db.bookSourceDao().allEnabled bookSourceList.clear()
for (item in bookSourceList) { bookSourceList.addAll(App.db.bookSourceDao().allEnabled)
//task取消时自动取消 by (scope = this@execute)
WebBook(item).searchBook(name, scope = this@execute, context = searchPool)
.timeout(30000L)
.onSuccess(Dispatchers.IO) {
if (it.isNotEmpty()) {
val searchBook = it[0]
if (searchBook.name == name && searchBook.author == author
&& !searchBook.coverUrl.isNullOrEmpty()
) {
App.db.searchBookDao().insert(searchBook)
if (!searchBooks.contains(searchBook)) {
searchBooks.add(searchBook)
searchBooksLiveData.postValue(searchBooks)
}
}
}
}
}
}.onStart {
searchStateData.postValue(true) searchStateData.postValue(true)
}.onCancel { initSearchPool()
searchStateData.postValue(false) for (i in 0 until threadCount) {
search()
}
} }
}
task?.invokeOnCompletion { private fun search() {
searchStateData.postValue(false) synchronized(this) {
if (searchIndex >= bookSourceList.lastIndex) {
return
}
searchIndex++
val source = bookSourceList[searchIndex]
val task = WebBook(source).searchBook(name, scope = this, context = searchPool!!)
.timeout(60000L)
.onSuccess(Dispatchers.IO) {
if (it.isNotEmpty()) {
val searchBook = it[0]
if (searchBook.name == name && searchBook.author == author
&& !searchBook.coverUrl.isNullOrEmpty()
) {
App.db.searchBookDao().insert(searchBook)
if (!searchBooks.contains(searchBook)) {
searchBooks.add(searchBook)
searchBooksLiveData.postValue(searchBooks)
}
}
}
}
.onFinally {
synchronized(this) {
if (searchIndex < bookSourceList.lastIndex) {
search()
} else {
searchIndex++
}
if (searchIndex >= bookSourceList.lastIndex + min(bookSourceList.size,
threadCount)
) {
searchStateData.postValue(false)
}
}
}
tasks.add(task)
} }
} }
fun stopSearch() { fun stopSearch() {
if (task?.isActive == true) { if (tasks.isEmpty) {
task?.cancel() startSearch()
} else { } else {
search() tasks.clear()
} }
} }
override fun onCleared() { override fun onCleared() {
super.onCleared() super.onCleared()
searchPool.close() searchPool?.close()
} }
} }

@ -25,7 +25,7 @@ import java.util.concurrent.Executors
import kotlin.math.min import kotlin.math.min
class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { class ChangeSourceViewModel(application: Application) : BaseViewModel(application) {
val threadCount = AppConfig.threadCount private val threadCount = AppConfig.threadCount
private var searchPool: ExecutorCoroutineDispatcher? = null private var searchPool: ExecutorCoroutineDispatcher? = null
val handler = Handler() val handler = Handler()
val searchStateData = MutableLiveData<Boolean>() val searchStateData = MutableLiveData<Boolean>()
@ -54,6 +54,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
private fun initSearchPool() { private fun initSearchPool() {
searchPool = Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher() searchPool = Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher()
searchIndex = -1
} }
fun loadDbSearchBook() { fun loadDbSearchBook() {

Loading…
Cancel
Save