mirror of
https://github.com/gedoor/legado.git
synced 2024-07-17 00:58:29 +08:00
优化
This commit is contained in:
parent
9d1aa1c5d6
commit
cc99eb1f03
@ -117,7 +117,6 @@ object PreferKey {
|
|||||||
const val welcomeShowIconDark = "welcomeShowIconDark"
|
const val welcomeShowIconDark = "welcomeShowIconDark"
|
||||||
const val pageTouchSlop = "pageTouchSlop"
|
const val pageTouchSlop = "pageTouchSlop"
|
||||||
const val showAddToShelfAlert = "showAddToShelfAlert"
|
const val showAddToShelfAlert = "showAddToShelfAlert"
|
||||||
const val asyncLoadImage = "asyncLoadImage"
|
|
||||||
const val ignoreAudioFocus = "ignoreAudioFocus"
|
const val ignoreAudioFocus = "ignoreAudioFocus"
|
||||||
const val parallelExportBook = "parallelExportBook"
|
const val parallelExportBook = "parallelExportBook"
|
||||||
const val progressBarBehavior = "progressBarBehavior"
|
const val progressBarBehavior = "progressBarBehavior"
|
||||||
|
@ -460,8 +460,6 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
|||||||
|
|
||||||
val showAddToShelfAlert get() = appCtx.getPrefBoolean(PreferKey.showAddToShelfAlert, true)
|
val showAddToShelfAlert get() = appCtx.getPrefBoolean(PreferKey.showAddToShelfAlert, true)
|
||||||
|
|
||||||
val asyncLoadImage get() = appCtx.getPrefBoolean(PreferKey.asyncLoadImage, false)
|
|
||||||
|
|
||||||
val ignoreAudioFocus get() = appCtx.getPrefBoolean(PreferKey.ignoreAudioFocus, false)
|
val ignoreAudioFocus get() = appCtx.getPrefBoolean(PreferKey.ignoreAudioFocus, false)
|
||||||
|
|
||||||
val onlyLatestBackup get() = appCtx.getPrefBoolean(PreferKey.onlyLatestBackup, true)
|
val onlyLatestBackup get() = appCtx.getPrefBoolean(PreferKey.onlyLatestBackup, true)
|
||||||
|
@ -6,9 +6,7 @@ import android.os.Build
|
|||||||
import android.util.Size
|
import android.util.Size
|
||||||
import androidx.collection.LruCache
|
import androidx.collection.LruCache
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.constant.AppLog
|
|
||||||
import io.legado.app.constant.AppLog.putDebug
|
import io.legado.app.constant.AppLog.putDebug
|
||||||
import io.legado.app.constant.PageAnim
|
|
||||||
import io.legado.app.data.entities.Book
|
import io.legado.app.data.entities.Book
|
||||||
import io.legado.app.data.entities.BookSource
|
import io.legado.app.data.entities.BookSource
|
||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
@ -16,10 +14,8 @@ import io.legado.app.help.book.BookHelp
|
|||||||
import io.legado.app.help.book.isEpub
|
import io.legado.app.help.book.isEpub
|
||||||
import io.legado.app.help.book.isPdf
|
import io.legado.app.help.book.isPdf
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.coroutine.Coroutine
|
|
||||||
import io.legado.app.model.localBook.EpubFile
|
import io.legado.app.model.localBook.EpubFile
|
||||||
import io.legado.app.model.localBook.PdfFile
|
import io.legado.app.model.localBook.PdfFile
|
||||||
import io.legado.app.utils.BitmapCache
|
|
||||||
import io.legado.app.utils.BitmapUtils
|
import io.legado.app.utils.BitmapUtils
|
||||||
import io.legado.app.utils.FileUtils
|
import io.legado.app.utils.FileUtils
|
||||||
import io.legado.app.utils.SvgUtils
|
import io.legado.app.utils.SvgUtils
|
||||||
@ -70,8 +66,7 @@ object ImageProvider {
|
|||||||
) {
|
) {
|
||||||
//错误图片不能释放,占位用,防止一直重复获取图片
|
//错误图片不能释放,占位用,防止一直重复获取图片
|
||||||
if (oldBitmap != errorBitmap) {
|
if (oldBitmap != errorBitmap) {
|
||||||
BitmapCache.add(oldBitmap)
|
oldBitmap.recycle()
|
||||||
//oldBitmap.recycle()
|
|
||||||
//putDebug("ImageProvider: trigger bitmap recycle. URI: $filePath")
|
//putDebug("ImageProvider: trigger bitmap recycle. URI: $filePath")
|
||||||
//putDebug("ImageProvider : cacheUsage ${size()}bytes / ${maxSize()}bytes")
|
//putDebug("ImageProvider : cacheUsage ${size()}bytes / ${maxSize()}bytes")
|
||||||
}
|
}
|
||||||
@ -160,9 +155,8 @@ object ImageProvider {
|
|||||||
book: Book,
|
book: Book,
|
||||||
src: String,
|
src: String,
|
||||||
width: Int,
|
width: Int,
|
||||||
height: Int? = null,
|
height: Int? = null
|
||||||
block: (() -> Unit)? = null
|
): Bitmap {
|
||||||
): Bitmap? {
|
|
||||||
//src为空白时 可能被净化替换掉了 或者规则失效
|
//src为空白时 可能被净化替换掉了 或者规则失效
|
||||||
if (book.getUseReplaceRule() && src.isBlank()) {
|
if (book.getUseReplaceRule() && src.isBlank()) {
|
||||||
book.setUseReplaceRule(false)
|
book.setUseReplaceRule(false)
|
||||||
@ -174,32 +168,6 @@ object ImageProvider {
|
|||||||
//bitmapLruCache的key同一改成缓存文件的路径
|
//bitmapLruCache的key同一改成缓存文件的路径
|
||||||
val cacheBitmap = getNotRecycled(vFile.absolutePath)
|
val cacheBitmap = getNotRecycled(vFile.absolutePath)
|
||||||
if (cacheBitmap != null) return cacheBitmap
|
if (cacheBitmap != null) return cacheBitmap
|
||||||
if (height != null && AppConfig.asyncLoadImage && ReadBook.pageAnim() == PageAnim.scrollPageAnim) {
|
|
||||||
if (asyncLoadingImages.contains(vFile.absolutePath)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
asyncLoadingImages.add(vFile.absolutePath)
|
|
||||||
Coroutine.async {
|
|
||||||
BitmapUtils.decodeBitmap(vFile.absolutePath, width, height)
|
|
||||||
?: SvgUtils.createBitmap(vFile.absolutePath, width, height)
|
|
||||||
?: throw NoStackTraceException(appCtx.getString(R.string.error_decode_bitmap))
|
|
||||||
}.onSuccess {
|
|
||||||
bitmapLruCache.run {
|
|
||||||
if (maxSize() < maxCacheSize && size() + it.byteCount > maxSize() && putCount() - evictionCount() < 5) {
|
|
||||||
resize(min(maxCacheSize, maxSize() + it.byteCount))
|
|
||||||
AppLog.put("图片缓存太小,自动扩增至${(maxSize() / M)}MB。")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bitmapLruCache.put(vFile.absolutePath, it)
|
|
||||||
}.onError {
|
|
||||||
//错误图片占位,防止重复获取
|
|
||||||
bitmapLruCache.put(vFile.absolutePath, errorBitmap)
|
|
||||||
}.onFinally {
|
|
||||||
asyncLoadingImages.remove(vFile.absolutePath)
|
|
||||||
block?.invoke()
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return kotlin.runCatching {
|
return kotlin.runCatching {
|
||||||
val bitmap = BitmapUtils.decodeBitmap(vFile.absolutePath, width, height)
|
val bitmap = BitmapUtils.decodeBitmap(vFile.absolutePath, width, height)
|
||||||
?: SvgUtils.createBitmap(vFile.absolutePath, width, height)
|
?: SvgUtils.createBitmap(vFile.absolutePath, width, height)
|
||||||
@ -214,7 +182,6 @@ object ImageProvider {
|
|||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
bitmapLruCache.evictAll()
|
bitmapLruCache.evictAll()
|
||||||
BitmapCache.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -964,9 +964,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
*/
|
*/
|
||||||
override fun pageChanged() {
|
override fun pageChanged() {
|
||||||
pageChanged = true
|
pageChanged = true
|
||||||
runOnUiThread {
|
binding.readView.onPageChange()
|
||||||
binding.readView.onPageChange()
|
|
||||||
}
|
|
||||||
handler.post {
|
handler.post {
|
||||||
upSeekBarProgress()
|
upSeekBarProgress()
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,7 @@ data class ImageColumn(
|
|||||||
src,
|
src,
|
||||||
(end - start).toInt(),
|
(end - start).toInt(),
|
||||||
height.toInt()
|
height.toInt()
|
||||||
) {
|
)
|
||||||
textLine.invalidate()
|
|
||||||
view.invalidate()
|
|
||||||
} ?: return
|
|
||||||
|
|
||||||
val rectF = if (textLine.isImage) {
|
val rectF = if (textLine.isImage) {
|
||||||
RectF(start, 0f, end, height)
|
RectF(start, 0f, end, height)
|
||||||
|
@ -1,104 +0,0 @@
|
|||||||
package io.legado.app.utils
|
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import java.lang.ref.SoftReference
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
object BitmapCache {
|
|
||||||
|
|
||||||
private val reusableBitmaps: MutableSet<SoftReference<Bitmap>> = ConcurrentHashMap.newKeySet()
|
|
||||||
|
|
||||||
fun add(bitmap: Bitmap) {
|
|
||||||
reusableBitmaps.add(SoftReference(bitmap))
|
|
||||||
trimSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clear() {
|
|
||||||
if (reusableBitmaps.isEmpty()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val iterator = reusableBitmaps.iterator()
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
val item = iterator.next().get() ?: continue
|
|
||||||
item.recycle()
|
|
||||||
iterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun trimSize() {
|
|
||||||
var byteCount = 0
|
|
||||||
val iterator = reusableBitmaps.iterator()
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
val item = iterator.next().get() ?: continue
|
|
||||||
if (byteCount > 128 * 1024 * 1024) {
|
|
||||||
item.recycle()
|
|
||||||
iterator.remove()
|
|
||||||
} else {
|
|
||||||
byteCount += item.byteCount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addInBitmapOptions(options: BitmapFactory.Options) {
|
|
||||||
// inBitmap only works with mutable bitmaps, so force the decoder to
|
|
||||||
// return mutable bitmaps.
|
|
||||||
options.inMutable = true
|
|
||||||
|
|
||||||
// Try to find a bitmap to use for inBitmap.
|
|
||||||
getBitmapFromReusableSet(options)?.also { inBitmap ->
|
|
||||||
// If a suitable bitmap has been found, set it as the value of
|
|
||||||
// inBitmap.
|
|
||||||
options.inBitmap = inBitmap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun getBitmapFromReusableSet(options: BitmapFactory.Options): Bitmap? {
|
|
||||||
if (reusableBitmaps.isEmpty()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
val iterator = reusableBitmaps.iterator()
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
val item = iterator.next().get() ?: continue
|
|
||||||
if (item.isMutable) {
|
|
||||||
// Check to see it the item can be used for inBitmap.
|
|
||||||
if (canUseForInBitmap(item, options)) {
|
|
||||||
// Remove from reusable set so it can't be used again.
|
|
||||||
iterator.remove()
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Remove from the set if the reference has been cleared.
|
|
||||||
iterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun canUseForInBitmap(
|
|
||||||
candidate: Bitmap,
|
|
||||||
targetOptions: BitmapFactory.Options
|
|
||||||
): Boolean {
|
|
||||||
// From Android 4.4 (KitKat) onward we can re-use if the byte size of
|
|
||||||
// the new bitmap is smaller than the reusable bitmap candidate
|
|
||||||
// allocation byte count.
|
|
||||||
val width: Int = targetOptions.outWidth / targetOptions.inSampleSize
|
|
||||||
val height: Int = targetOptions.outHeight / targetOptions.inSampleSize
|
|
||||||
val byteCount: Int = width * height * getBytesPerPixel(candidate.config)
|
|
||||||
return byteCount <= candidate.allocationByteCount
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper function to return the byte usage per pixel of a bitmap based on its configuration.
|
|
||||||
*/
|
|
||||||
private fun getBytesPerPixel(config: Bitmap.Config): Int {
|
|
||||||
return when (config) {
|
|
||||||
Bitmap.Config.ARGB_8888 -> 4
|
|
||||||
Bitmap.Config.RGB_565, Bitmap.Config.ARGB_4444 -> 2
|
|
||||||
Bitmap.Config.ALPHA_8 -> 1
|
|
||||||
else -> 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -34,7 +34,6 @@ object BitmapUtils {
|
|||||||
BitmapFactory.decodeFileDescriptor(fis.fd, null, op)
|
BitmapFactory.decodeFileDescriptor(fis.fd, null, op)
|
||||||
op.inSampleSize = calculateInSampleSize(op, width, height)
|
op.inSampleSize = calculateInSampleSize(op, width, height)
|
||||||
op.inJustDecodeBounds = false
|
op.inJustDecodeBounds = false
|
||||||
BitmapCache.addInBitmapOptions(op)
|
|
||||||
BitmapFactory.decodeFileDescriptor(fis.fd, null, op)
|
BitmapFactory.decodeFileDescriptor(fis.fd, null, op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,13 +136,6 @@
|
|||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
app:isBottomBackground="true" />
|
app:isBottomBackground="true" />
|
||||||
|
|
||||||
<io.legado.app.lib.prefs.SwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="asyncLoadImage"
|
|
||||||
android:title="@string/async_load_image"
|
|
||||||
app:iconSpaceReserved="false"
|
|
||||||
app:isBottomBackground="true" />
|
|
||||||
|
|
||||||
<io.legado.app.lib.prefs.SwitchPreference
|
<io.legado.app.lib.prefs.SwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="noAnimScrollPage"
|
android:key="noAnimScrollPage"
|
||||||
|
Loading…
Reference in New Issue
Block a user