pull/36/head
kunfei 5 years ago
parent e9279fd103
commit 5c594ffbd5
  1. 15
      app/src/main/java/io/legado/app/base/BaseViewModel.kt
  2. 29
      app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt
  3. 5
      app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt
  4. 12
      app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt

@ -8,17 +8,26 @@ import io.legado.app.help.coroutine.Coroutine
import kotlinx.coroutines.* import kotlinx.coroutines.*
import org.jetbrains.anko.AnkoLogger import org.jetbrains.anko.AnkoLogger
import org.jetbrains.anko.toast 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 { AnkoLogger {
val context: Context by lazy { this.getApplication<App>() } val context: Context by lazy { this.getApplication<App>() }
fun <T> execute(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> T): Coroutine<T> { fun <T> execute(
scope: CoroutineScope = this,
context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO),
block: suspend CoroutineScope.() -> T
): Coroutine<T> {
return Coroutine.async(scope) { block() } return Coroutine.async(scope) { block() }
} }
fun <R> submit(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> Deferred<R>): Coroutine<R> { fun <R> submit(
scope: CoroutineScope = this,
block: suspend CoroutineScope.() -> Deferred<R>
): Coroutine<R> {
return Coroutine.async(scope) { block().await() } return Coroutine.async(scope) { block().await() }
} }

@ -1,18 +1,25 @@
package io.legado.app.help.coroutine package io.legado.app.help.coroutine
import android.util.Log
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class Coroutine<T>(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) { class Coroutine<T>(
scope: CoroutineScope,
context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO),
block: suspend CoroutineScope.() -> T
) {
companion object { companion object {
val DEFAULT = MainScope() val DEFAULT = MainScope()
fun <T> async(scope: CoroutineScope = DEFAULT, block: suspend CoroutineScope.() -> T): Coroutine<T> { fun <T> async(
return Coroutine(scope, block) scope: CoroutineScope = DEFAULT,
context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO),
block: suspend CoroutineScope.() -> T
): Coroutine<T> {
return Coroutine(scope, context, block)
} }
} }
@ -37,7 +44,7 @@ class Coroutine<T>(scope: CoroutineScope, block: suspend CoroutineScope.() -> T)
get() = job.isCompleted get() = job.isCompleted
init { init {
this.job = executeInternal(scope, block) this.job = executeInternal(scope, context, block)
} }
fun timeout(timeMillis: () -> Long): Coroutine<T> { fun timeout(timeMillis: () -> Long): Coroutine<T> {
@ -101,11 +108,15 @@ class Coroutine<T>(scope: CoroutineScope, block: suspend CoroutineScope.() -> T)
return job.invokeOnCompletion(handler) 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 { return scope.plus(Dispatchers.Main).launch {
try { try {
start?.let { dispatchVoidCallback(this, it) } 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) } success?.let { dispatchCallback(this, value, it) }
} catch (e: Throwable) { } catch (e: Throwable) {
val consume: Boolean = errorReturn?.value?.let { value -> val consume: Boolean = errorReturn?.value?.let { value ->
@ -147,11 +158,11 @@ class Coroutine<T>(scope: CoroutineScope, block: suspend CoroutineScope.() -> T)
} }
private suspend inline fun executeBlock( private suspend inline fun executeBlock(
scope: CoroutineScope, context: CoroutineContext,
timeMillis: Long, timeMillis: Long,
noinline block: suspend CoroutineScope.() -> T noinline block: suspend CoroutineScope.() -> T
): T? { ): T? {
return withContext(scope.coroutineContext.plus(Dispatchers.IO)) { return withContext(context) {
if (timeMillis > 0L) withTimeout(timeMillis) { if (timeMillis > 0L) withTimeout(timeMillis) {
block() block()
} else block() } else block()

@ -107,7 +107,10 @@ class SearchActivity : VMBaseActivity<SearchViewModel>(R.layout.activity_book_se
private fun initOtherView() { private fun initOtherView() {
tv_clear_history.onClick { viewModel.clearHistory() } tv_clear_history.onClick { viewModel.clearHistory() }
fb_stop.onClick { viewModel.stop() } fb_stop.onClick {
viewModel.stop()
refresh_progress_bar.isAutoLoading = false
}
} }
private fun initData() { private fun initData() {

@ -8,9 +8,13 @@ import io.legado.app.data.entities.SearchKeyword
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.WebBook import io.legado.app.model.WebBook
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import java.util.concurrent.Executors
class SearchViewModel(application: Application) : BaseViewModel(application) { class SearchViewModel(application: Application) : BaseViewModel(application) {
private var searchPool = Executors.newFixedThreadPool(99).asCoroutineDispatcher()
private var task: Coroutine<*>? = null private var task: Coroutine<*>? = null
var searchKey: String = "" var searchKey: String = ""
var startTime: Long = 0 var startTime: Long = 0
@ -26,7 +30,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
searchKey = key searchKey = key
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
start?.invoke() start?.invoke()
task = execute { task = execute(context = searchPool) {
//onCleared时自动取消 //onCleared时自动取消
val bookSourceList = App.db.bookSourceDao().allEnabled val bookSourceList = App.db.bookSourceDao().allEnabled
for (item in bookSourceList) { for (item in bookSourceList) {
@ -53,6 +57,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
} }
fun stop() { fun stop() {
searchPool.cancel()
task?.cancel() task?.cancel()
} }
@ -77,4 +82,9 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
App.db.searchKeywordDao().deleteAll() App.db.searchKeywordDao().deleteAll()
} }
} }
override fun onCleared() {
searchPool.close()
super.onCleared()
}
} }

Loading…
Cancel
Save