Merge remote-tracking branch 'origin/master'

pull/32/head
kunfei 5 years ago
commit 10abf12674
  1. 17
      app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt
  2. 2
      app/src/main/java/io/legado/app/base/adapter/ItemViewDelegate.kt
  3. 23
      app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt
  4. 3
      app/src/main/java/io/legado/app/model/WebBook.kt
  5. 61
      app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt
  6. 136
      app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt
  7. 7
      app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt
  8. 33
      app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt

@ -198,8 +198,21 @@ abstract class CommonRecyclerAdapter<ITEM>(protected val context: Context) : Rec
synchronized(lock) { synchronized(lock) {
val size = getActualItemCount() val size = getActualItemCount()
if (oldPosition in 0 until size && newPosition in 0 until size) { if (oldPosition in 0 until size && newPosition in 0 until size) {
Collections.swap(this.items, oldPosition + getHeaderCount(), newPosition + getHeaderCount()) val srcPosition = oldPosition + getHeaderCount()
notifyDataSetChanged() val targetPosition = newPosition + getHeaderCount()
Collections.swap(this.items, srcPosition, targetPosition)
notifyItemChanged(srcPosition)
notifyItemChanged(targetPosition)
}
}
}
fun updateItem(item: ITEM) {
synchronized(lock) {
val index = this.items.indexOf(item)
if (index >= 0) {
this.items[index] = item
notifyItemChanged(index)
} }
} }
} }

@ -7,7 +7,7 @@ import android.content.Context
* *
* item代理 * item代理
*/ */
abstract class ItemViewDelegate<in ITEM>(protected val context: Context, val layoutId: Int) { abstract class ItemViewDelegate<ITEM>(protected val context: Context, val layoutId: Int) {
abstract fun convert(holder: ItemViewHolder, item: ITEM, payloads: MutableList<Any>) abstract fun convert(holder: ItemViewHolder, item: ITEM, payloads: MutableList<Any>)

@ -30,6 +30,15 @@ class Coroutine<T>() {
private var errorReturn: Result<T>? = null private var errorReturn: Result<T>? = null
val isCancelled: Boolean
get() = job?.isCancelled ?: false
val isActive: Boolean
get() = job?.isActive ?: false
val isCompleted: Boolean
get() = job?.isCompleted ?: false
private constructor( private constructor(
scope: CoroutineScope, scope: CoroutineScope,
block: suspend CoroutineScope.() -> T block: suspend CoroutineScope.() -> T
@ -106,24 +115,24 @@ class Coroutine<T>() {
private suspend fun executeInternal(block: suspend CoroutineScope.() -> T) { private suspend fun executeInternal(block: suspend CoroutineScope.() -> T) {
tryCatch( tryCatch(
{ {
start?.let { it() } start?.invoke(this)
val result = executeBlock(block, timeMillis ?: 0L) val result = executeBlock(block, timeMillis ?: 0L)
success?.let { it(result) } success?.invoke(this, result)
}, },
{ e -> { e ->
val consume: Boolean = errorReturn?.value?.let { value -> val consume: Boolean = errorReturn?.value?.let { value ->
success?.let { it(value) } success?.invoke(this, value)
true true
} ?: false } ?: false
if (!consume) { if (!consume) {
error?.let { it(e) } error?.invoke(this, e)
} }
}, },
{ {
finally?.let { it() } finally?.invoke(this)
}) })
} }
@ -142,9 +151,9 @@ class Coroutine<T>() {
try { try {
coroutineScope { tryBlock() } coroutineScope { tryBlock() }
} catch (e: Throwable) { } catch (e: Throwable) {
coroutineScope { errorBlock?.let { it(e) } } coroutineScope { errorBlock?.invoke(this, e) }
} finally { } finally {
coroutineScope { finallyBlock?.let { it() } } coroutineScope { finallyBlock?.invoke(this) }
} }
} }

@ -13,6 +13,9 @@ import io.legado.app.model.webbook.BookList
class WebBook(private val bookSource: BookSource) { class WebBook(private val bookSource: BookSource) {
val sourceUrl: String
get() = bookSource.bookSourceUrl
fun searchBook(key: String, page: Int?, isSearch: Boolean = true): Coroutine<List<SearchBook>> { fun searchBook(key: String, page: Int?, isSearch: Boolean = true): Coroutine<List<SearchBook>> {
return Coroutine.async { return Coroutine.async {
bookSource.getSearchRule().searchUrl?.let { searchUrl -> bookSource.getSearchRule().searchUrl?.let { searchUrl ->

@ -4,23 +4,26 @@ import android.annotation.SuppressLint
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.WebBook import io.legado.app.model.WebBook
import io.legado.app.utils.htmlFormat import io.legado.app.utils.htmlFormat
import io.legado.app.utils.isAbsUrl
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
class SourceDebug(private val webBook: WebBook, callback: Callback) { class SourceDebug(private val webBook: WebBook, callback: Callback) {
companion object { companion object {
var debugSource: String? = null private var debugSource: String? = null
var callback: Callback? = null private var callback: Callback? = null
private val tasks: MutableList<Coroutine<*>> = mutableListOf()
@SuppressLint("ConstantLocale") @SuppressLint("ConstantLocale")
private val DEBUG_TIME_FORMAT = SimpleDateFormat("[mm:ss.SSS]", Locale.getDefault()) private val DEBUG_TIME_FORMAT = SimpleDateFormat("[mm:ss.SSS]", Locale.getDefault())
private val startTime: Long = System.currentTimeMillis() private val startTime: Long = System.currentTimeMillis()
fun printLog(sourceUrl: String?, state: Int, msg: String, print: Boolean = true, isHtml: Boolean = false) { fun printLog(sourceUrl: String?, state: Int, msg: String, print: Boolean = true, isHtml: Boolean = false) {
if (debugSource != sourceUrl) return if (debugSource != sourceUrl || callback == null || !print) return
if (!print) return
var printMsg = msg var printMsg = msg
if (isHtml) { if (isHtml) {
printMsg = printMsg.htmlFormat() printMsg = printMsg.htmlFormat()
@ -29,18 +32,46 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) {
String.format("%s %s", DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime)), printMsg) String.format("%s %s", DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime)), printMsg)
callback?.printLog(state, printMsg) callback?.printLog(state, printMsg)
} }
}
interface Callback { fun cancelDebug(destroy: Boolean = false) {
fun printLog(state: Int, msg: String) tasks.forEach {
if (!it.isCancelled) {
it.cancel()
}
}
tasks.clear()
if (destroy) {
debugSource = null
callback = null
}
}
} }
init { init {
debugSource = webBook.sourceUrl
SourceDebug.callback = callback SourceDebug.callback = callback
} }
fun startDebug(key: String) {
cancelDebug()
with(webBook) {
if (key.isAbsUrl()) {
val book = Book()
book.origin = sourceUrl
book.bookUrl = key
printLog(sourceUrl, 1, "开始访问$key")
infoDebug(book)
} else {
printLog(sourceUrl, 1, "开始搜索关键字$key")
searchDebug(key)
}
}
}
fun searchDebug(key: String) { fun searchDebug(key: String) {
webBook.searchBook(key, 1) val search = webBook.searchBook(key, 1)
.onSuccess { searchBooks -> .onSuccess { searchBooks ->
searchBooks?.let { searchBooks?.let {
if (searchBooks.isNotEmpty()) { if (searchBooks.isNotEmpty()) {
@ -51,20 +82,22 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) {
.onError { .onError {
printLog(debugSource, -1, it.localizedMessage) printLog(debugSource, -1, it.localizedMessage)
} }
tasks.add(search)
} }
fun infoDebug(book: Book) { fun infoDebug(book: Book) {
webBook.getBookInfo(book) val info = webBook.getBookInfo(book)
.onSuccess { .onSuccess {
tocDebug(book) tocDebug(book)
} }
.onError { .onError {
printLog(debugSource, -1, it.localizedMessage) printLog(debugSource, -1, it.localizedMessage)
} }
tasks.add(info)
} }
private fun tocDebug(book: Book) { private fun tocDebug(book: Book) {
webBook.getChapterList(book) val chapterList = webBook.getChapterList(book)
.onSuccess { chapterList -> .onSuccess { chapterList ->
chapterList?.let { chapterList?.let {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
@ -75,10 +108,11 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) {
.onError { .onError {
printLog(debugSource, -1, it.localizedMessage) printLog(debugSource, -1, it.localizedMessage)
} }
tasks.add(chapterList)
} }
private fun contentDebug(book: Book, bookChapter: BookChapter) { private fun contentDebug(book: Book, bookChapter: BookChapter) {
webBook.getContent(book, bookChapter) val content = webBook.getContent(book, bookChapter)
.onSuccess { content -> .onSuccess { content ->
content?.let { content?.let {
printLog(debugSource, 1000, it) printLog(debugSource, 1000, it)
@ -87,6 +121,11 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) {
.onError { .onError {
printLog(debugSource, -1, it.localizedMessage) printLog(debugSource, -1, it.localizedMessage)
} }
tasks.add(content)
}
interface Callback {
fun printLog(state: Int, msg: String)
} }
fun printLog( fun printLog(

@ -10,6 +10,8 @@ import io.legado.app.data.entities.SearchBook
import io.legado.app.help.http.HttpHelper import io.legado.app.help.http.HttpHelper
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
class SearchViewModel(application: Application) : BaseViewModel(application) { class SearchViewModel(application: Application) : BaseViewModel(application) {
@ -19,86 +21,68 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
private val channel = Channel<Int>()//协程之间通信 private val channel = Channel<Int>()//协程之间通信
fun search(start: (() -> Unit)? = null, finally: (() -> Unit)? = null) { fun search(start: (() -> Unit)? = null, finally: (() -> Unit)? = null) {
// launch { launch {
// repeat(1000) { repeat(1000) {
// channel.send(it) channel.send(it)
// } }
// } }
//
//
// val c = execute { val c = execute {
//
// Log.e("TAG1", "start") val response: String = HttpHelper.getApiService<CommonHttpApi>(
// "http://www.baidu.com"
// val response: String = HttpHelper.getApiService<CommonHttpApi>( ).get("http://www.baidu.com").await()
// "http://www.baidu.com"
// ).get("http://www.baidu.com").await() delay(2000L)
//
// Log.e("TAG1", "result: $response") response
// }
// delay(2000L) .onStart {
// Log.e("TAG!", "start")
// response start?.let { it() }
// } }
// .onStart { .onSuccess {
// Log.e("TAG!", "start") Log.e("TAG!", "success: $it")
// start?.let { it() } }
// } .onError {
Log.e("TAG!", "error: $it")
}
.onFinally {
Log.e("TAG!", "finally")
if (finally != null) {
finally()
}
}
val c2 = plus(c)
// .timeout { 100L }
// .onErrorReturn { "error return2" }
.onStart {
//会拦截掉c的onStart
Log.e("TAG!", "start2")
start?.let { it() }
}
// .onSuccess { // .onSuccess {
// Log.e("TAG!", "success: $it") // Log.e("TAG!", "success2: $it")
// }
// .onError {
// Log.e("TAG!", "error: $it")
// }
// .onFinally {
// Log.e("TAG!", "finally")
// if (finally != null) {
// finally()
// }
// }
//
// val c2 = plus(c)
//// .timeout { 100L }
//// .onErrorReturn { "error return2" }
// .onStart {
// //会拦截掉c的onStart
// Log.e("TAG!", "start2")
// start?.let { it() }
// }
//// .onSuccess {
//// Log.e("TAG!", "success2: $it")
//// }
// .onError {
// Log.e("TAG!", "error2: $it")
// } // }
// .onFinally { .onError {
// Log.e("TAG!", "finally2") Log.e("TAG!", "error2: $it")
// if (finally != null) { }
// finally() .onFinally {
// } Log.e("TAG!", "finally2")
// if (finally != null) {
// Log.e("TAG!", "rec2: " + channel.receive()) finally()
// } }
//
// launch {
// delay(1500L)
//// c2.cancel()
//
//// c.cancel()
// }
//
//
// launch {
// val list = test()
// println("size: ${list.size} $list")
// }
Log.e("TAG!", "rec2: " + channel.receive())
}
execute { // execute {
test(this) // test(this)
}.onSuccess { // }.onSuccess {
println("size: ${it?.size} $it") // println("size: ${it?.size} $it")
} // }
} }
suspend fun test(scope: CoroutineScope): MutableList<String> { suspend fun test(scope: CoroutineScope): MutableList<String> {

@ -7,10 +7,8 @@ import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseActivity import io.legado.app.base.BaseActivity
import io.legado.app.data.entities.BookSource
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.ThemeStore
import io.legado.app.model.webbook.SourceDebug
import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.activity_source_debug.*
import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.android.synthetic.main.view_title_bar.*
@ -71,9 +69,4 @@ class SourceDebugActivity : BaseActivity<SourceDebugModel>() {
toast("未获取到书源") toast("未获取到书源")
}) })
} }
override fun onDestroy() {
SourceDebug.debugSource = null
super.onDestroy()
}
} }

@ -4,48 +4,39 @@ import android.app.Application
import androidx.lifecycle.MutableLiveData 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.data.entities.Book
import io.legado.app.data.entities.BookSource
import io.legado.app.help.EventMessage import io.legado.app.help.EventMessage
import io.legado.app.model.WebBook import io.legado.app.model.WebBook
import io.legado.app.model.webbook.SourceDebug import io.legado.app.model.webbook.SourceDebug
import io.legado.app.utils.isAbsUrl
class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback { class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback {
val logs: MutableLiveData<EventMessage> = MutableLiveData() val logs: MutableLiveData<EventMessage> = MutableLiveData()
private var bookSource: BookSource? = null private var webBook: WebBook? = null
fun init(sourceUrl: String?) { fun init(sourceUrl: String?) {
sourceUrl?.let { sourceUrl?.let {
//优先使用这个,不会抛出异常 //优先使用这个,不会抛出异常
execute { execute {
bookSource = App.db.bookSourceDao().findByKey(sourceUrl) val bookSource = App.db.bookSourceDao().findByKey(sourceUrl)
bookSource?.let { webBook = WebBook(it) }
} }
} }
} }
fun startDebug(key: String, start: (() -> Unit)? = null, error: (() -> Unit)? = null) { fun startDebug(key: String, start: (() -> Unit)? = null, error: (() -> Unit)? = null) {
bookSource?.let { webBook?.let {
start?.let { it() } start?.invoke()
SourceDebug.debugSource = it.bookSourceUrl SourceDebug(it, this).startDebug(key)
if (key.isAbsUrl()) { } ?: error?.invoke()
val book = Book()
book.origin = it.bookSourceUrl
book.bookUrl = key
SourceDebug(WebBook(it), this)
.printLog(it.bookSourceUrl, 1, "开始访问$key")
.infoDebug(book)
} else {
SourceDebug(WebBook(it), this)
.printLog(it.bookSourceUrl, 1, "开始搜索关键字$key")
.searchDebug(key)
}
} ?: error?.let { it() }
} }
override fun printLog(state: Int, msg: String) { override fun printLog(state: Int, msg: String) {
logs.postValue(EventMessage.obtain(state, msg)) logs.postValue(EventMessage.obtain(state, msg))
} }
override fun onCleared() {
super.onCleared()
SourceDebug.cancelDebug(true)
}
} }

Loading…
Cancel
Save