diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index 1aa8452c9..d59bb15f7 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -8,17 +8,26 @@ import io.legado.app.help.coroutine.Coroutine import kotlinx.coroutines.* import org.jetbrains.anko.AnkoLogger import org.jetbrains.anko.toast +import kotlin.coroutines.CoroutineContext -open class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope by MainScope(), +open class BaseViewModel(application: Application) : AndroidViewModel(application), + CoroutineScope by MainScope(), AnkoLogger { val context: Context by lazy { this.getApplication() } - fun execute(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> T): Coroutine { + fun execute( + scope: CoroutineScope = this, + context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + block: suspend CoroutineScope.() -> T + ): Coroutine { return Coroutine.async(scope) { block() } } - fun submit(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> Deferred): Coroutine { + fun submit( + scope: CoroutineScope = this, + block: suspend CoroutineScope.() -> Deferred + ): Coroutine { return Coroutine.async(scope) { block().await() } } diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index 5b8c3d2c0..e72a3df22 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -1,18 +1,25 @@ package io.legado.app.help.coroutine -import android.util.Log import kotlinx.coroutines.* import kotlin.coroutines.CoroutineContext -class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) { +class Coroutine( + scope: CoroutineScope, + context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + block: suspend CoroutineScope.() -> T +) { companion object { val DEFAULT = MainScope() - fun async(scope: CoroutineScope = DEFAULT, block: suspend CoroutineScope.() -> T): Coroutine { - return Coroutine(scope, block) + fun async( + scope: CoroutineScope = DEFAULT, + context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + block: suspend CoroutineScope.() -> T + ): Coroutine { + return Coroutine(scope, context, block) } } @@ -37,7 +44,7 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) get() = job.isCompleted init { - this.job = executeInternal(scope, block) + this.job = executeInternal(scope, context, block) } fun timeout(timeMillis: () -> Long): Coroutine { @@ -101,11 +108,15 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) return job.invokeOnCompletion(handler) } - private fun executeInternal(scope: CoroutineScope, block: suspend CoroutineScope.() -> T): Job { + private fun executeInternal( + scope: CoroutineScope, + context: CoroutineContext, + block: suspend CoroutineScope.() -> T + ): Job { return scope.plus(Dispatchers.Main).launch { try { start?.let { dispatchVoidCallback(this, it) } - val value = executeBlock(scope, timeMillis ?: 0L, block) + val value = executeBlock(context, timeMillis ?: 0L, block) success?.let { dispatchCallback(this, value, it) } } catch (e: Throwable) { val consume: Boolean = errorReturn?.value?.let { value -> @@ -147,11 +158,11 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) } private suspend inline fun executeBlock( - scope: CoroutineScope, + context: CoroutineContext, timeMillis: Long, noinline block: suspend CoroutineScope.() -> T ): T? { - return withContext(scope.coroutineContext.plus(Dispatchers.IO)) { + return withContext(context) { if (timeMillis > 0L) withTimeout(timeMillis) { block() } else block() diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 1ed4fae13..bc25fa64f 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -107,7 +107,10 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se private fun initOtherView() { tv_clear_history.onClick { viewModel.clearHistory() } - fb_stop.onClick { viewModel.stop() } + fb_stop.onClick { + viewModel.stop() + refresh_progress_bar.isAutoLoading = false + } } private fun initData() { diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index 011a13d8a..0890ef013 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -8,9 +8,13 @@ import io.legado.app.data.entities.SearchKeyword import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.cancel import kotlinx.coroutines.delay +import java.util.concurrent.Executors class SearchViewModel(application: Application) : BaseViewModel(application) { + private var searchPool = Executors.newFixedThreadPool(99).asCoroutineDispatcher() private var task: Coroutine<*>? = null var searchKey: String = "" var startTime: Long = 0 @@ -26,7 +30,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { searchKey = key startTime = System.currentTimeMillis() start?.invoke() - task = execute { + task = execute(context = searchPool) { //onCleared时自动取消 val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { @@ -53,6 +57,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } fun stop() { + searchPool.cancel() task?.cancel() } @@ -77,4 +82,9 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { App.db.searchKeywordDao().deleteAll() } } + + override fun onCleared() { + searchPool.close() + super.onCleared() + } }