优化
This commit is contained in:
@@ -16,6 +16,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
abstract class BaseService : LifecycleService() {
|
abstract class BaseService : LifecycleService() {
|
||||||
@@ -28,8 +29,9 @@ abstract class BaseService : LifecycleService() {
|
|||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
executeContext: CoroutineContext = Dispatchers.Main,
|
executeContext: CoroutineContext = Dispatchers.Main,
|
||||||
|
semaphore: Semaphore? = null,
|
||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
) = Coroutine.async(scope, context, start, executeContext, block)
|
) = Coroutine.async(scope, context, start, executeContext, semaphore, block)
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@@ -22,18 +23,22 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio
|
|||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
executeContext: CoroutineContext = Dispatchers.Main,
|
executeContext: CoroutineContext = Dispatchers.Main,
|
||||||
|
semaphore: Semaphore? = null,
|
||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
): Coroutine<T> {
|
): Coroutine<T> {
|
||||||
return Coroutine.async(scope, context, start, executeContext, block)
|
return Coroutine.async(scope, context, start, executeContext, semaphore, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> executeLazy(
|
fun <T> executeLazy(
|
||||||
scope: CoroutineScope = viewModelScope,
|
scope: CoroutineScope = viewModelScope,
|
||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
executeContext: CoroutineContext = Dispatchers.Main,
|
executeContext: CoroutineContext = Dispatchers.Main,
|
||||||
|
semaphore: Semaphore? = null,
|
||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
): Coroutine<T> {
|
): Coroutine<T> {
|
||||||
return Coroutine.async(scope, context, CoroutineStart.LAZY, executeContext, block)
|
return Coroutine.async(
|
||||||
|
scope, context, CoroutineStart.LAZY, executeContext, semaphore, block
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <R> submit(
|
fun <R> submit(
|
||||||
|
|||||||
@@ -132,6 +132,9 @@ interface BookDao {
|
|||||||
@Query("select exists(select 1 from books where bookUrl = :bookUrl)")
|
@Query("select exists(select 1 from books where bookUrl = :bookUrl)")
|
||||||
fun has(bookUrl: String): Boolean
|
fun has(bookUrl: String): Boolean
|
||||||
|
|
||||||
|
@Query("select exists(select 1 from books where name = :name and author = :author)")
|
||||||
|
fun has(name: String, author: String): Boolean
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""select exists(select 1 from books where type & ${BookType.local} > 0
|
"""select exists(select 1 from books where type & ${BookType.local} > 0
|
||||||
and (originName = :fileName or (origin != '${BookType.localTag}' and origin like '%' || :fileName)))"""
|
and (originName = :fileName or (origin != '${BookType.localTag}' and origin like '%' || :fileName)))"""
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import kotlinx.coroutines.ensureActive
|
|||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@@ -23,10 +24,11 @@ import kotlin.coroutines.CoroutineContext
|
|||||||
*/
|
*/
|
||||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||||
class Coroutine<T>(
|
class Coroutine<T>(
|
||||||
val scope: CoroutineScope,
|
private val scope: CoroutineScope,
|
||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
val startOption: CoroutineStart = CoroutineStart.DEFAULT,
|
private val startOption: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
val executeContext: CoroutineContext = Dispatchers.Main,
|
private val executeContext: CoroutineContext = Dispatchers.Main,
|
||||||
|
private val semaphore: Semaphore? = null,
|
||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -39,9 +41,10 @@ class Coroutine<T>(
|
|||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
executeContext: CoroutineContext = Dispatchers.Main,
|
executeContext: CoroutineContext = Dispatchers.Main,
|
||||||
|
semaphore: Semaphore? = null,
|
||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
): Coroutine<T> {
|
): Coroutine<T> {
|
||||||
return Coroutine(scope, context, start, executeContext, block)
|
return Coroutine(scope, context, start, executeContext, semaphore, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -169,6 +172,7 @@ class Coroutine<T>(
|
|||||||
block: suspend CoroutineScope.() -> T
|
block: suspend CoroutineScope.() -> T
|
||||||
): Job {
|
): Job {
|
||||||
return (scope.plus(executeContext)).launch(start = startOption) {
|
return (scope.plus(executeContext)).launch(start = startOption) {
|
||||||
|
semaphore?.acquire()
|
||||||
try {
|
try {
|
||||||
start?.let { dispatchVoidCallback(this, it) }
|
start?.let { dispatchVoidCallback(this, it) }
|
||||||
ensureActive()
|
ensureActive()
|
||||||
@@ -185,7 +189,11 @@ class Coroutine<T>(
|
|||||||
error?.let { dispatchCallback(this, e, it) }
|
error?.let { dispatchCallback(this, e, it) }
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
finally?.let { dispatchVoidCallback(this, it) }
|
try {
|
||||||
|
finally?.let { dispatchVoidCallback(this, it) }
|
||||||
|
} finally {
|
||||||
|
semaphore?.release()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import kotlinx.coroutines.CoroutineStart
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.sync.Semaphore
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlinx.coroutines.sync.withPermit
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.coroutineContext
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
@@ -283,12 +282,14 @@ object WebBook {
|
|||||||
executeContext: CoroutineContext = Dispatchers.Main,
|
executeContext: CoroutineContext = Dispatchers.Main,
|
||||||
semaphore: Semaphore? = null,
|
semaphore: Semaphore? = null,
|
||||||
): Coroutine<String> {
|
): Coroutine<String> {
|
||||||
return Coroutine.async(scope, context, start = start, executeContext = executeContext) {
|
return Coroutine.async(
|
||||||
semaphore?.withPermit {
|
scope,
|
||||||
getContentAwait(bookSource, book, bookChapter, nextChapterUrl, needSave)
|
context,
|
||||||
} ?: run {
|
start = start,
|
||||||
getContentAwait(bookSource, book, bookChapter, nextChapterUrl, needSave)
|
executeContext = executeContext,
|
||||||
}
|
semaphore = semaphore
|
||||||
|
) {
|
||||||
|
getContentAwait(bookSource, book, bookChapter, nextChapterUrl, needSave)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,8 +361,9 @@ object WebBook {
|
|||||||
name: String,
|
name: String,
|
||||||
author: String,
|
author: String,
|
||||||
context: CoroutineContext = Dispatchers.IO,
|
context: CoroutineContext = Dispatchers.IO,
|
||||||
|
semaphore: Semaphore? = null,
|
||||||
): Coroutine<Pair<Book, BookSource>> {
|
): Coroutine<Pair<Book, BookSource>> {
|
||||||
return Coroutine.async(scope, context) {
|
return Coroutine.async(scope, context, semaphore = semaphore) {
|
||||||
for (s in bookSourceParts) {
|
for (s in bookSourceParts) {
|
||||||
val source = s.getBookSource() ?: continue
|
val source = s.getBookSource() ?: continue
|
||||||
val book = preciseSearchAwait(source, name, author).getOrNull()
|
val book = preciseSearchAwait(source, name, author).getOrNull()
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import io.legado.app.data.appDb
|
|||||||
import io.legado.app.data.entities.Book
|
import io.legado.app.data.entities.Book
|
||||||
import io.legado.app.data.entities.BookSourcePart
|
import io.legado.app.data.entities.BookSourcePart
|
||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.coroutine.Coroutine
|
import io.legado.app.help.coroutine.Coroutine
|
||||||
import io.legado.app.help.http.decompressed
|
import io.legado.app.help.http.decompressed
|
||||||
import io.legado.app.help.http.newCallResponseBody
|
import io.legado.app.help.http.newCallResponseBody
|
||||||
@@ -24,7 +25,8 @@ import io.legado.app.utils.isAbsUrl
|
|||||||
import io.legado.app.utils.isJsonArray
|
import io.legado.app.utils.isJsonArray
|
||||||
import io.legado.app.utils.printOnDebug
|
import io.legado.app.utils.printOnDebug
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
|
import kotlinx.coroutines.sync.withPermit
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.OutputStreamWriter
|
import java.io.OutputStreamWriter
|
||||||
@@ -154,21 +156,26 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application)
|
|||||||
private fun importBookshelfByJson(json: String, groupId: Long) {
|
private fun importBookshelfByJson(json: String, groupId: Long) {
|
||||||
execute {
|
execute {
|
||||||
val bookSourceParts = appDb.bookSourceDao.allEnabledPart
|
val bookSourceParts = appDb.bookSourceDao.allEnabledPart
|
||||||
|
val semaphore = Semaphore(AppConfig.threadCount + 1)
|
||||||
GSON.fromJsonArray<Map<String, String?>>(json).getOrThrow().forEach { bookInfo ->
|
GSON.fromJsonArray<Map<String, String?>>(json).getOrThrow().forEach { bookInfo ->
|
||||||
if (!isActive) return@execute
|
|
||||||
val name = bookInfo["name"] ?: ""
|
val name = bookInfo["name"] ?: ""
|
||||||
val author = bookInfo["author"] ?: ""
|
val author = bookInfo["author"] ?: ""
|
||||||
if (name.isNotEmpty() && appDb.bookDao.getBook(name, author) == null) {
|
if (name.isEmpty() || appDb.bookDao.has(name, author)) {
|
||||||
WebBook.preciseSearch(this, bookSourceParts, name, author)
|
return@forEach
|
||||||
.onSuccess {
|
}
|
||||||
val book = it.first
|
semaphore.withPermit {
|
||||||
if (groupId > 0) {
|
WebBook.preciseSearch(
|
||||||
book.group = groupId
|
this, bookSourceParts, name, author,
|
||||||
}
|
semaphore = semaphore
|
||||||
book.save()
|
).onSuccess {
|
||||||
}.onError { e ->
|
val book = it.first
|
||||||
context.toastOnUi(e.localizedMessage)
|
if (groupId > 0) {
|
||||||
|
book.group = groupId
|
||||||
}
|
}
|
||||||
|
book.save()
|
||||||
|
}.onError { e ->
|
||||||
|
context.toastOnUi(e.localizedMessage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onError {
|
}.onError {
|
||||||
|
|||||||
Reference in New Issue
Block a user