优化搜索代码

pull/346/head
gedoor 4 years ago
parent 2442e747d3
commit 757d01a699
  1. 95
      app/src/main/java/io/legado/app/model/webBook/SearchBookModel.kt
  2. 16
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt
  3. 3
      app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt

@ -1,86 +1,109 @@
package io.legado.app.model.webBook
import io.legado.app.App
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.SearchBook
import io.legado.app.help.AppConfig
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.help.coroutine.CompositeCoroutine
import io.legado.app.utils.getPrefString
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.ExecutorCoroutineDispatcher
import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executors
import kotlin.math.min
class SearchBookModel(private val scope: CoroutineScope, private val callBack: CallBack) {
private var searchPool =
Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher()
private var mSearchId = System.currentTimeMillis()
val threadCount = AppConfig.threadCount
private var searchPool: ExecutorCoroutineDispatcher? = null
private var mSearchId = 0L
private var searchPage = 1
private var searchKey: String = ""
private var task: Coroutine<*>? = null
private var tasks = CompositeCoroutine()
private var bookSourceList = arrayListOf<BookSource>()
@Volatile
private var searchIndex = -1
private fun initSearchPool() {
searchPool =
Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher()
searchPool = Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher()
}
fun search(searchId: Long, key: String) {
callBack.onSearchStart()
if (searchId != mSearchId) {
task?.cancel()
searchPool.close()
initSearchPool()
mSearchId = searchId
searchPage = 1
if (key.isEmpty()) {
callBack.onSearchCancel()
return
} else {
this.searchKey = key
}
} else {
searchPage++
if (mSearchId != 0L) {
close()
}
task = Coroutine.async(scope, searchPool) {
initSearchPool()
mSearchId = searchId
searchPage = 1
val searchGroup = App.INSTANCE.getPrefString("searchGroup") ?: ""
val bookSourceList = if (searchGroup.isBlank()) {
App.db.bookSourceDao().allEnabled
bookSourceList.clear()
if (searchGroup.isBlank()) {
bookSourceList.addAll(App.db.bookSourceDao().allEnabled)
} else {
bookSourceList.addAll(App.db.bookSourceDao().getEnabledByGroup(searchGroup))
}
} else {
App.db.bookSourceDao().getEnabledByGroup(searchGroup)
searchPage++
}
for (i in 0 until threadCount) {
search(searchId)
}
for (item in bookSourceList) {
//task取消时自动取消 by (scope = this@execute)
WebBook(item).searchBook(
}
private fun search(searchId: Long) {
synchronized(this) {
if (searchIndex >= bookSourceList.lastIndex) {
return
}
searchIndex++
val source = bookSourceList[searchIndex]
val task = WebBook(source).searchBook(
searchKey,
searchPage,
scope = this,
context = searchPool
)
.timeout(30000L)
scope = scope,
context = searchPool!!
).timeout(30000L)
.onSuccess(IO) {
if (searchId == mSearchId) {
callBack.onSearchSuccess(it)
}
}
.onFinally {
synchronized(this) {
if (searchIndex < bookSourceList.lastIndex) {
search(searchId)
} else {
searchIndex++
}
}.onStart {
callBack.onSearchStart()
}
task?.invokeOnCompletion {
if (searchId == mSearchId) {
if (searchIndex >= bookSourceList.lastIndex + min(bookSourceList.size,
threadCount)
) {
callBack.onSearchFinish()
}
}
}
tasks.add(task)
}
}
fun cancelSearch() {
task?.cancel()
mSearchId = 0
close()
callBack.onSearchCancel()
}
fun close() {
task?.cancel()
mSearchId = 0
searchPool.close()
tasks.clear()
searchPool?.close()
mSearchId = 0L
}
interface CallBack {

@ -22,10 +22,11 @@ import kotlinx.coroutines.asCoroutineDispatcher
import org.jetbrains.anko.debug
import java.util.concurrent.CopyOnWriteArraySet
import java.util.concurrent.Executors
import kotlin.math.min
class ChangeSourceViewModel(application: Application) : BaseViewModel(application) {
val threadCount = AppConfig.threadCount
private lateinit var searchPool: ExecutorCoroutineDispatcher
private var searchPool: ExecutorCoroutineDispatcher? = null
val handler = Handler()
val searchStateData = MutableLiveData<Boolean>()
val searchBooksLiveData = MutableLiveData<List<SearchBook>>()
@ -106,9 +107,12 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
private fun search() {
synchronized(this) {
if (searchIndex >= bookSourceList.lastIndex) {
return
}
searchIndex++
val source = bookSourceList[searchIndex]
val task = WebBook(source).searchBook(name, scope = this, context = searchPool)
val task = WebBook(source).searchBook(name, scope = this, context = searchPool!!)
.timeout(60000L)
.onSuccess(IO) {
it.forEach { searchBook ->
@ -133,7 +137,9 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
} else {
searchIndex++
}
if (searchIndex >= bookSourceList.lastIndex + threadCount) {
if (searchIndex >= bookSourceList.lastIndex + min(bookSourceList.size,
threadCount)
) {
searchStateData.postValue(false)
}
}
@ -194,14 +200,14 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
startSearch()
} else {
tasks.clear()
searchPool.close()
searchPool?.close()
searchStateData.postValue(false)
}
}
override fun onCleared() {
super.onCleared()
searchPool.close()
searchPool?.close()
}
fun disableSource(searchBook: SearchBook) {

@ -30,7 +30,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application),
* 开始搜索
*/
fun search(key: String) {
if (searchKey != key && key.isNotEmpty()) {
if ((searchKey != key && key.isEmpty()) || key.isNotEmpty()) {
searchBookModel.cancelSearch()
searchBooks.clear()
searchBookLiveData.postValue(searchBooks)
@ -54,6 +54,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application),
override fun onSearchStart() {
isSearchLiveData.postValue(true)
isLoading = true
}
override fun onSearchSuccess(searchBooks: ArrayList<SearchBook>) {

Loading…
Cancel
Save