mirror of
https://github.com/gedoor/legado.git
synced 2024-07-06 23:47:49 +08:00
优化
This commit is contained in:
parent
9d1aa1c5d6
commit
cc99eb1f03
@ -117,7 +117,6 @@ object PreferKey {
|
||||
const val welcomeShowIconDark = "welcomeShowIconDark"
|
||||
const val pageTouchSlop = "pageTouchSlop"
|
||||
const val showAddToShelfAlert = "showAddToShelfAlert"
|
||||
const val asyncLoadImage = "asyncLoadImage"
|
||||
const val ignoreAudioFocus = "ignoreAudioFocus"
|
||||
const val parallelExportBook = "parallelExportBook"
|
||||
const val progressBarBehavior = "progressBarBehavior"
|
||||
|
@ -460,8 +460,6 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
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 onlyLatestBackup get() = appCtx.getPrefBoolean(PreferKey.onlyLatestBackup, true)
|
||||
|
@ -6,9 +6,7 @@ import android.os.Build
|
||||
import android.util.Size
|
||||
import androidx.collection.LruCache
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.AppLog
|
||||
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.BookSource
|
||||
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.isPdf
|
||||
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.PdfFile
|
||||
import io.legado.app.utils.BitmapCache
|
||||
import io.legado.app.utils.BitmapUtils
|
||||
import io.legado.app.utils.FileUtils
|
||||
import io.legado.app.utils.SvgUtils
|
||||
@ -70,8 +66,7 @@ object ImageProvider {
|
||||
) {
|
||||
//错误图片不能释放,占位用,防止一直重复获取图片
|
||||
if (oldBitmap != errorBitmap) {
|
||||
BitmapCache.add(oldBitmap)
|
||||
//oldBitmap.recycle()
|
||||
oldBitmap.recycle()
|
||||
//putDebug("ImageProvider: trigger bitmap recycle. URI: $filePath")
|
||||
//putDebug("ImageProvider : cacheUsage ${size()}bytes / ${maxSize()}bytes")
|
||||
}
|
||||
@ -160,9 +155,8 @@ object ImageProvider {
|
||||
book: Book,
|
||||
src: String,
|
||||
width: Int,
|
||||
height: Int? = null,
|
||||
block: (() -> Unit)? = null
|
||||
): Bitmap? {
|
||||
height: Int? = null
|
||||
): Bitmap {
|
||||
//src为空白时 可能被净化替换掉了 或者规则失效
|
||||
if (book.getUseReplaceRule() && src.isBlank()) {
|
||||
book.setUseReplaceRule(false)
|
||||
@ -174,32 +168,6 @@ object ImageProvider {
|
||||
//bitmapLruCache的key同一改成缓存文件的路径
|
||||
val cacheBitmap = getNotRecycled(vFile.absolutePath)
|
||||
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 {
|
||||
val bitmap = BitmapUtils.decodeBitmap(vFile.absolutePath, width, height)
|
||||
?: SvgUtils.createBitmap(vFile.absolutePath, width, height)
|
||||
@ -214,7 +182,6 @@ object ImageProvider {
|
||||
|
||||
fun clear() {
|
||||
bitmapLruCache.evictAll()
|
||||
BitmapCache.clear()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -964,9 +964,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
*/
|
||||
override fun pageChanged() {
|
||||
pageChanged = true
|
||||
runOnUiThread {
|
||||
binding.readView.onPageChange()
|
||||
}
|
||||
binding.readView.onPageChange()
|
||||
handler.post {
|
||||
upSeekBarProgress()
|
||||
}
|
||||
|
@ -32,10 +32,7 @@ data class ImageColumn(
|
||||
src,
|
||||
(end - start).toInt(),
|
||||
height.toInt()
|
||||
) {
|
||||
textLine.invalidate()
|
||||
view.invalidate()
|
||||
} ?: return
|
||||
)
|
||||
|
||||
val rectF = if (textLine.isImage) {
|
||||
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)
|
||||
op.inSampleSize = calculateInSampleSize(op, width, height)
|
||||
op.inJustDecodeBounds = false
|
||||
BitmapCache.addInBitmapOptions(op)
|
||||
BitmapFactory.decodeFileDescriptor(fis.fd, null, op)
|
||||
}
|
||||
}
|
||||
|
@ -136,13 +136,6 @@
|
||||
app:iconSpaceReserved="false"
|
||||
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
|
||||
android:defaultValue="false"
|
||||
android:key="noAnimScrollPage"
|
||||
|
Loading…
Reference in New Issue
Block a user