This commit is contained in:
Horis
2025-05-15 17:43:24 +08:00
parent e8a21b6ef8
commit dc9e500712
8 changed files with 23 additions and 106 deletions
@@ -90,7 +90,7 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
* 存储异常和参数信息
*/
private val paramsMap by lazy {
val map = HashMap<String, String>()
val map = LinkedHashMap<String, String>()
kotlin.runCatching {
//获取系统信息
map["MANUFACTURER"] = Build.MANUFACTURER
@@ -104,6 +104,7 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
e.toString()
}
map["packageName"] = appCtx.packageName
map["heapSize"] = Runtime.getRuntime().maxMemory().toString()
//获取app版本信息
AppConst.appInfo.let {
map["versionName"] = it.versionName
@@ -6,6 +6,7 @@ import io.legado.app.BuildConfig
import io.legado.app.constant.AppConst
import io.legado.app.constant.PreferKey
import io.legado.app.data.appDb
import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.getPrefInt
import io.legado.app.utils.getPrefLong
@@ -37,7 +38,8 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
var clickActionBR = appCtx.getPrefInt(PreferKey.clickActionBR, 1)
var themeMode = appCtx.getPrefString(PreferKey.themeMode, "0")
var useDefaultCover = appCtx.getPrefBoolean(PreferKey.useDefaultCover, false)
var optimizeRender = appCtx.getPrefBoolean(PreferKey.optimizeRender, false)
var optimizeRender = CanvasRecorderFactory.isSupport
&& appCtx.getPrefBoolean(PreferKey.optimizeRender, false)
var recordLog = appCtx.getPrefBoolean(PreferKey.recordLog)
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
@@ -87,8 +89,8 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
PreferKey.useDefaultCover -> useDefaultCover =
appCtx.getPrefBoolean(PreferKey.useDefaultCover, false)
PreferKey.optimizeRender -> optimizeRender =
appCtx.getPrefBoolean(PreferKey.optimizeRender, false)
PreferKey.optimizeRender -> optimizeRender = CanvasRecorderFactory.isSupport
&& appCtx.getPrefBoolean(PreferKey.optimizeRender, false)
PreferKey.recordLog -> recordLog = appCtx.getPrefBoolean(PreferKey.recordLog)
@@ -25,9 +25,11 @@ import io.legado.app.model.ReadBook
import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.ui.book.read.page.provider.ChapterProvider
import io.legado.app.ui.widget.number.NumberPickerDialog
import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
import io.legado.app.utils.dpToPx
import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.postEvent
import io.legado.app.utils.removePref
import io.legado.app.utils.setEdgeEffectColor
class MoreConfigDialog : BasePrefDialogFragment() {
@@ -83,6 +85,10 @@ class MoreConfigDialog : BasePrefDialogFragment() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_config_read)
upPreferenceSummary(PreferKey.pageTouchSlop, slopSquare.toString())
if (!CanvasRecorderFactory.isSupport) {
removePref(PreferKey.optimizeRender)
preferenceScreen.removePreferenceRecursively(PreferKey.optimizeRender)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -35,7 +35,6 @@ import io.legado.app.ui.book.read.page.provider.ChapterProvider
import io.legado.app.ui.book.read.page.provider.LayoutProgressListener
import io.legado.app.ui.book.read.page.provider.TextPageFactory
import io.legado.app.utils.activity
import io.legado.app.utils.canvasrecorder.pools.BitmapPool
import io.legado.app.utils.invisible
import io.legado.app.utils.longToastOnUi
import io.legado.app.utils.showDialogFragment
@@ -485,7 +484,6 @@ class ReadView(context: Context, attrs: AttributeSet) :
pageDelegate?.onDestroy()
curPage.cancelSelect()
invalidateTextPage()
BitmapPool.clear()
}
/**
@@ -124,6 +124,7 @@ object LogUtils {
}
append("WebViewUserAgent=").append(userAgent).append("\n")
append("packageName=").append(appCtx.packageName).append("\n")
append("heapSize=").append(Runtime.getRuntime().maxMemory()).append("\n")
//获取app版本信息
AppConst.appInfo.let {
append("versionName=").append(it.versionName).append("\n")
@@ -7,6 +7,7 @@ object CanvasRecorderFactory {
private val atLeastApi24 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
private val atLeastApi29 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
val isSupport = atLeastApi24
// issue 3868
fun create(locked: Boolean = false): CanvasRecorder {
@@ -3,8 +3,9 @@ package io.legado.app.utils.canvasrecorder
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import io.legado.app.utils.canvasrecorder.pools.BitmapPool
import com.bumptech.glide.Glide
import io.legado.app.utils.canvasrecorder.pools.CanvasPool
import splitties.init.appCtx
class CanvasRecorderImpl : BaseCanvasRecorder() {
@@ -19,14 +20,14 @@ class CanvasRecorderImpl : BaseCanvasRecorder() {
return
}
if (bitmap == null) {
bitmap = BitmapPool.obtain(width, height)
bitmap = bitmapPool.get(width, height, Bitmap.Config.ARGB_8888)
}
if (bitmap!!.width != width || bitmap!!.height != height) {
if (canReconfigure(width, height)) {
if (bitmap!!.isMutable && canReconfigure(width, height)) {
bitmap!!.reconfigure(width, height, Bitmap.Config.ARGB_8888)
} else {
BitmapPool.recycle(bitmap!!)
bitmap = BitmapPool.obtain(width, height)
bitmapPool.put(bitmap!!)
bitmap = bitmapPool.get(width, height, Bitmap.Config.ARGB_8888)
}
}
}
@@ -57,12 +58,13 @@ class CanvasRecorderImpl : BaseCanvasRecorder() {
override fun recycle() {
super.recycle()
val bitmap = bitmap ?: return
BitmapPool.recycle(bitmap)
bitmapPool.put(bitmap)
this.bitmap = null
}
companion object {
private val canvasPool = CanvasPool(2)
private val bitmapPool = Glide.get(appCtx).bitmapPool
}
}
@@ -1,94 +0,0 @@
package io.legado.app.utils.canvasrecorder.pools
import android.graphics.Bitmap
import io.legado.app.help.globalExecutor
import java.util.concurrent.ConcurrentHashMap
object BitmapPool {
private val reusableBitmaps: MutableSet<Bitmap> = ConcurrentHashMap.newKeySet()
fun recycle(bitmap: Bitmap) {
reusableBitmaps.add(bitmap)
trimSize()
}
fun clear() {
if (reusableBitmaps.isEmpty()) {
return
}
globalExecutor.execute {
val iterator = reusableBitmaps.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
iterator.remove()
item.recycle()
}
}
}
private fun trimSize() {
globalExecutor.execute {
var byteCount = 0
val iterator = reusableBitmaps.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
if (byteCount > 64 * 1024 * 1024) {
iterator.remove()
item.recycle()
} else {
byteCount += item.byteCount
}
}
}
}
fun obtain(width: Int, height: Int): Bitmap {
if (reusableBitmaps.isEmpty()) {
return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
}
val iterator = reusableBitmaps.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
if (item.isMutable) {
// Check to see it the item can be used for inBitmap.
if (canReconfigure(item, width, height)) {
// Remove from reusable set so it can't be used again.
iterator.remove()
item.reconfigure(width, height, Bitmap.Config.ARGB_8888)
return item
}
} else {
// Remove from the set if the reference has been cleared.
iterator.remove()
}
}
return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
}
private fun canReconfigure(
candidate: Bitmap,
width: Int,
height: Int
): 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 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
}
}
}