mirror of
https://github.com/gedoor/legado.git
synced 2024-07-06 23:47:49 +08:00
优化
This commit is contained in:
parent
c45f138fd5
commit
4119231dd0
@ -1,6 +1,5 @@
|
||||
package io.legado.app.help.coroutine
|
||||
|
||||
import android.os.Looper
|
||||
import io.legado.app.utils.printOnDebug
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CompletionHandler
|
||||
@ -16,7 +15,6 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.plus
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
@ -35,9 +33,6 @@ class Coroutine<T>(
|
||||
companion object {
|
||||
|
||||
private val DEFAULT = MainScope()
|
||||
private val launchExecutor = Executors.newSingleThreadExecutor()
|
||||
private val mainThread = Looper.getMainLooper().thread
|
||||
private val isMainThread inline get() = mainThread === Thread.currentThread()
|
||||
|
||||
fun <T> async(
|
||||
scope: CoroutineScope = DEFAULT,
|
||||
@ -51,7 +46,7 @@ class Coroutine<T>(
|
||||
|
||||
}
|
||||
|
||||
private val job: Job by lazy { executeInternal(context, block) }
|
||||
private val job: Job
|
||||
|
||||
private var start: VoidCallback? = null
|
||||
private var success: Callback<T>? = null
|
||||
@ -72,13 +67,7 @@ class Coroutine<T>(
|
||||
get() = job.isCompleted
|
||||
|
||||
init {
|
||||
if (context == Dispatchers.Main.immediate && isMainThread) {
|
||||
job
|
||||
} else {
|
||||
launchExecutor.execute {
|
||||
job
|
||||
}
|
||||
}
|
||||
this.job = executeInternal(context, block)
|
||||
}
|
||||
|
||||
fun timeout(timeMillis: () -> Long): Coroutine<T> {
|
||||
|
@ -116,6 +116,7 @@ import io.legado.app.utils.toastOnUi
|
||||
import io.legado.app.utils.visible
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.asExecutor
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -220,6 +221,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
private var reloadContent = false
|
||||
private val handler by lazy { buildMainHandler() }
|
||||
private val screenOffRunnable by lazy { Runnable { keepScreenOn(false) } }
|
||||
private val executor = IO.asExecutor()
|
||||
|
||||
//恢复跳转前进度对话框的交互结果
|
||||
private var confirmRestoreProcess: Boolean? = null
|
||||
@ -908,7 +910,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
}
|
||||
|
||||
override fun upMenuView() {
|
||||
lifecycleScope.launch {
|
||||
handler.post {
|
||||
binding.readMenu.upBookView()
|
||||
}
|
||||
}
|
||||
@ -930,7 +932,6 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
ReadAloud.upTtsProgress(this)
|
||||
}
|
||||
loadStates = true
|
||||
binding.readView.onContentLoadFinish()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -964,8 +965,13 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
*/
|
||||
override fun pageChanged() {
|
||||
pageChanged = true
|
||||
runOnUiThread {
|
||||
binding.readView.onPageChange()
|
||||
}
|
||||
handler.post {
|
||||
upSeekBarProgress()
|
||||
}
|
||||
executor.execute {
|
||||
startBackupJob()
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import androidx.core.graphics.withTranslation
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.PageAnim
|
||||
import io.legado.app.data.entities.Bookmark
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.model.ReadBook
|
||||
@ -24,12 +23,12 @@ import io.legado.app.ui.book.read.page.entities.column.TextColumn
|
||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||
import io.legado.app.ui.book.read.page.provider.TextPageFactory
|
||||
import io.legado.app.ui.widget.dialog.PhotoDialog
|
||||
import io.legado.app.utils.PictureMirror
|
||||
import io.legado.app.utils.activity
|
||||
import io.legado.app.utils.getCompatColor
|
||||
import io.legado.app.utils.showDialogFragment
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
@ -58,10 +57,12 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
||||
private val pageFactory get() = callBack.pageFactory
|
||||
private val pageDelegate get() = callBack.pageDelegate
|
||||
private var pageOffset = 0
|
||||
private val pictureMirror = PictureMirror()
|
||||
private val isNoAnim get() = ReadBook.pageAnim() == PageAnim.noAnim
|
||||
private var autoPager: AutoPager? = null
|
||||
private val renderThread by lazy { Executors.newSingleThreadExecutor() }
|
||||
private val renderThread by lazy {
|
||||
Executors.newSingleThreadExecutor {
|
||||
Thread(it, "TextPageRender")
|
||||
}
|
||||
}
|
||||
private val renderRunnable by lazy { Runnable { preRenderPage() } }
|
||||
|
||||
//绘制图片的paint
|
||||
@ -99,13 +100,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
||||
}
|
||||
check(!visibleRect.isEmpty) { "visibleRect 为空" }
|
||||
canvas.clipRect(visibleRect)
|
||||
if (!callBack.isScroll && !isNoAnim) {
|
||||
pictureMirror.draw(canvas, width, height) {
|
||||
drawPage(this)
|
||||
}
|
||||
} else {
|
||||
drawPage(canvas)
|
||||
}
|
||||
drawPage(canvas)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,11 +172,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun invalidate() {
|
||||
super.invalidate()
|
||||
pictureMirror.invalidate()
|
||||
}
|
||||
|
||||
fun submitPreRenderTask() {
|
||||
renderThread.submit(renderRunnable)
|
||||
}
|
||||
|
@ -644,12 +644,7 @@ class ReadView(context: Context, attrs: AttributeSet) :
|
||||
autoPager.resume()
|
||||
}
|
||||
|
||||
override fun onPageChange() {
|
||||
autoPager.reset()
|
||||
curPage.submitPreRenderTask()
|
||||
}
|
||||
|
||||
fun onContentLoadFinish() {
|
||||
fun onPageChange() {
|
||||
autoPager.reset()
|
||||
curPage.submitPreRenderTask()
|
||||
}
|
||||
|
@ -21,5 +21,4 @@ interface DataSource {
|
||||
|
||||
fun upContent(relativePosition: Int = 0, resetPageOffset: Boolean = true)
|
||||
|
||||
fun onPageChange()
|
||||
}
|
@ -4,6 +4,8 @@ package io.legado.app.ui.book.read.page.entities
|
||||
import androidx.annotation.Keep
|
||||
import io.legado.app.data.entities.BookChapter
|
||||
import io.legado.app.data.entities.ReplaceRule
|
||||
import io.legado.app.utils.fastBinarySearchBy
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
@ -85,12 +87,15 @@ data class TextChapter(
|
||||
* @return 已读长度
|
||||
*/
|
||||
fun getReadLength(pageIndex: Int): Int {
|
||||
return pages[min(pageIndex, lastIndex)].lines.first().chapterPosition
|
||||
/*
|
||||
var length = 0
|
||||
val maxIndex = min(pageIndex, pages.size)
|
||||
for (index in 0 until maxIndex) {
|
||||
length += pages[index].charSize
|
||||
}
|
||||
return length
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,6 +190,15 @@ data class TextChapter(
|
||||
* @return 根据索引位置获取所在页
|
||||
*/
|
||||
fun getPageIndexByCharIndex(charIndex: Int): Int {
|
||||
val index = pages.fastBinarySearchBy(charIndex) {
|
||||
it.lines.first().chapterPosition
|
||||
}
|
||||
return if (index >= 0) {
|
||||
index
|
||||
} else {
|
||||
abs(index + 1) - 1
|
||||
}
|
||||
/* 相当于以下实现
|
||||
var length = 0
|
||||
for (i in pages.indices) {
|
||||
val page = pages[i]
|
||||
@ -194,6 +208,7 @@ data class TextChapter(
|
||||
}
|
||||
}
|
||||
return pages.lastIndex
|
||||
*/
|
||||
}
|
||||
|
||||
fun clearSearchResult() {
|
||||
|
@ -264,7 +264,7 @@ data class TextPage(
|
||||
}
|
||||
|
||||
fun draw(view: ContentTextView, canvas: Canvas?) {
|
||||
pictureMirror.draw(canvas, view.width, height.toInt()) {
|
||||
pictureMirror.drawLocked(canvas, view.width, height.toInt(), view) {
|
||||
drawPage(view, this)
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ class TextPageFactory(dataSource: DataSource) : PageFactory<TextPage>(dataSource
|
||||
ReadBook.setPageIndex(pageIndex.plus(1))
|
||||
}
|
||||
if (upContent) upContent(resetPageOffset = false)
|
||||
dataSource.onPageChange()
|
||||
true
|
||||
} else
|
||||
false
|
||||
@ -64,7 +63,6 @@ class TextPageFactory(dataSource: DataSource) : PageFactory<TextPage>(dataSource
|
||||
ReadBook.setPageIndex(pageIndex.minus(1))
|
||||
}
|
||||
if (upContent) upContent(resetPageOffset = false)
|
||||
dataSource.onPageChange()
|
||||
true
|
||||
} else
|
||||
false
|
||||
|
@ -7,3 +7,33 @@ fun List<Float>.fastSum(): Float {
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
inline fun <T> List<T>.fastBinarySearch(
|
||||
fromIndex: Int = 0,
|
||||
toIndex: Int = size,
|
||||
comparison: (T) -> Int
|
||||
): Int {
|
||||
var low = fromIndex
|
||||
var high = toIndex - 1
|
||||
|
||||
while (low <= high) {
|
||||
val mid = (low + high).ushr(1) // safe from overflows
|
||||
val midVal = get(mid)
|
||||
val cmp = comparison(midVal)
|
||||
|
||||
if (cmp < 0)
|
||||
low = mid + 1
|
||||
else if (cmp > 0)
|
||||
high = mid - 1
|
||||
else
|
||||
return mid // key found
|
||||
}
|
||||
return -(low + 1) // key not found
|
||||
}
|
||||
|
||||
inline fun <T, K : Comparable<K>> List<T>.fastBinarySearchBy(
|
||||
key: K?,
|
||||
fromIndex: Int = 0,
|
||||
toIndex: Int = size,
|
||||
crossinline selector: (T) -> K?
|
||||
): Int = fastBinarySearch(fromIndex, toIndex) { compareValues(selector(it), key) }
|
||||
|
@ -3,6 +3,7 @@ package io.legado.app.utils
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Picture
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import androidx.core.graphics.record
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
@ -12,16 +13,31 @@ class PictureMirror {
|
||||
@Volatile
|
||||
var isDirty = true
|
||||
val lock = ReentrantLock()
|
||||
@Volatile
|
||||
var scheduleInvalidateView: View? = null
|
||||
|
||||
inline fun draw(canvas: Canvas?, width: Int, height: Int, block: Canvas.() -> Unit) {
|
||||
inline fun drawLocked(
|
||||
canvas: Canvas?,
|
||||
width: Int,
|
||||
height: Int,
|
||||
view: View? = null,
|
||||
block: Canvas.() -> Unit
|
||||
) {
|
||||
if (atLeastApi23) {
|
||||
if (picture == null) picture = Picture()
|
||||
val picture = picture!!
|
||||
if (isDirty) {
|
||||
if (!lock.tryLock()) return
|
||||
if (!lock.tryLock()) {
|
||||
if (canvas != null && view != null) {
|
||||
scheduleInvalidateView = view
|
||||
}
|
||||
return
|
||||
}
|
||||
try {
|
||||
picture.record(width, height, block)
|
||||
isDirty = false
|
||||
scheduleInvalidateView?.postInvalidate()
|
||||
scheduleInvalidateView = null
|
||||
} finally {
|
||||
lock.unlock()
|
||||
}
|
||||
@ -32,6 +48,28 @@ class PictureMirror {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 非线程安全,多线程调用可能会崩溃
|
||||
*/
|
||||
inline fun draw(
|
||||
canvas: Canvas?,
|
||||
width: Int,
|
||||
height: Int,
|
||||
block: Canvas.() -> Unit
|
||||
) {
|
||||
if (atLeastApi23) {
|
||||
if (picture == null) picture = Picture()
|
||||
val picture = picture!!
|
||||
if (isDirty) {
|
||||
picture.record(width, height, block)
|
||||
isDirty = false
|
||||
}
|
||||
canvas?.drawPicture(picture)
|
||||
} else {
|
||||
canvas?.block()
|
||||
}
|
||||
}
|
||||
|
||||
fun invalidate() {
|
||||
isDirty = true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user