perf(image): 优化图片加载性能
- 使用 BitmapDecodeHelper 替换 BitmapFactory 进行采样解码 - 添加单线程执行器进行异步图片解码处理 - 实现图片视图布局完成后再进行尺寸计算和加载 - 防止因 Activity 销毁导致的内存泄漏问题 - 在 SprayingFinishActivity、SprayingOCRActivity 和 SprayingResultActivity 中统一图片加载逻辑
这个提交包含在:
父节点
ff6a0c3a33
当前提交
7310127d56
@ -2,10 +2,11 @@ package com.nova.brain.glass.ui
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.BitmapFactory
|
import androidx.core.view.doOnLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.nova.brain.glass.R
|
import com.nova.brain.glass.R
|
||||||
import com.nova.brain.glass.databinding.ActivitySprayingFinishBinding
|
import com.nova.brain.glass.databinding.ActivitySprayingFinishBinding
|
||||||
|
import com.nova.brain.glass.helper.BitmapDecodeHelper
|
||||||
import com.nova.brain.glass.helper.OfflineCmdListener
|
import com.nova.brain.glass.helper.OfflineCmdListener
|
||||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||||
import com.nova.brain.glass.helper.SprayingPhotoManager
|
import com.nova.brain.glass.helper.SprayingPhotoManager
|
||||||
@ -15,6 +16,7 @@ import com.xuqm.base.adapter.BasePagedAdapter
|
|||||||
import com.xuqm.base.adapter.CommonPagedAdapter
|
import com.xuqm.base.adapter.CommonPagedAdapter
|
||||||
import com.xuqm.base.adapter.ViewHolder
|
import com.xuqm.base.adapter.ViewHolder
|
||||||
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
|
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
class SprayingFinishActivity :
|
class SprayingFinishActivity :
|
||||||
BaseListFormLayoutNormalActivity<ItemItem, SprayingFinishVM, ActivitySprayingFinishBinding>() {
|
BaseListFormLayoutNormalActivity<ItemItem, SprayingFinishVM, ActivitySprayingFinishBinding>() {
|
||||||
@ -22,6 +24,7 @@ class SprayingFinishActivity :
|
|||||||
override fun fullscreen(): Boolean = true
|
override fun fullscreen(): Boolean = true
|
||||||
|
|
||||||
override fun getRecyclerOrientation(): Int = RecyclerView.VERTICAL
|
override fun getRecyclerOrientation(): Int = RecyclerView.VERTICAL
|
||||||
|
private val imageDecodeExecutor = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
private val listener = object : OfflineCmdListener {
|
private val listener = object : OfflineCmdListener {
|
||||||
override fun onOfflineCmd(cmd: String) {
|
override fun onOfflineCmd(cmd: String) {
|
||||||
@ -52,7 +55,21 @@ class SprayingFinishActivity :
|
|||||||
val imageViews = listOf(binding.photo1, binding.photo2, binding.photo3)
|
val imageViews = listOf(binding.photo1, binding.photo2, binding.photo3)
|
||||||
imageViews.forEach { it.setImageDrawable(null) }
|
imageViews.forEach { it.setImageDrawable(null) }
|
||||||
photos.forEachIndexed { index, path ->
|
photos.forEachIndexed { index, path ->
|
||||||
imageViews.getOrNull(index)?.setImageBitmap(BitmapFactory.decodeFile(path))
|
imageViews.getOrNull(index)?.let { imageView ->
|
||||||
|
imageView.doOnLayout {
|
||||||
|
val targetWidth = imageView.width.coerceAtLeast(1)
|
||||||
|
val targetHeight = imageView.height.coerceAtLeast(1)
|
||||||
|
imageDecodeExecutor.execute {
|
||||||
|
val bitmap = BitmapDecodeHelper.decodeSampledBitmap(path, targetWidth, targetHeight)
|
||||||
|
runOnUiThread {
|
||||||
|
if (isFinishing || isDestroyed) {
|
||||||
|
return@runOnUiThread
|
||||||
|
}
|
||||||
|
imageView.setImageBitmap(bitmap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
package com.nova.brain.glass.ui
|
package com.nova.brain.glass.ui
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.os.CountDownTimer
|
import android.os.CountDownTimer
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import androidx.core.view.doOnLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.nova.brain.glass.R
|
import com.nova.brain.glass.R
|
||||||
import com.nova.brain.glass.databinding.ActivitySprayingOcrBinding
|
import com.nova.brain.glass.databinding.ActivitySprayingOcrBinding
|
||||||
|
import com.nova.brain.glass.helper.BitmapDecodeHelper
|
||||||
import com.nova.brain.glass.helper.OfflineCmdListener
|
import com.nova.brain.glass.helper.OfflineCmdListener
|
||||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||||
import com.nova.brain.glass.helper.SprayingPhotoManager
|
import com.nova.brain.glass.helper.SprayingPhotoManager
|
||||||
@ -24,6 +25,7 @@ import com.xuqm.base.common.LogHelper
|
|||||||
import com.xuqm.base.extensions.showMessage
|
import com.xuqm.base.extensions.showMessage
|
||||||
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
|
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.concurrent.Executors
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
class SprayingOCRActivity :
|
class SprayingOCRActivity :
|
||||||
@ -63,6 +65,7 @@ class SprayingOCRActivity :
|
|||||||
}
|
}
|
||||||
private val photoCallbackId = UUID.randomUUID().toString()
|
private val photoCallbackId = UUID.randomUUID().toString()
|
||||||
private var resultCountdown: CountDownTimer? = null
|
private var resultCountdown: CountDownTimer? = null
|
||||||
|
private val imageDecodeExecutor = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
private val mPhotoFileCallback = object : PhotoFileCallback.Stub() {
|
private val mPhotoFileCallback = object : PhotoFileCallback.Stub() {
|
||||||
override fun onTakePhoto(path: String) {
|
override fun onTakePhoto(path: String) {
|
||||||
@ -139,9 +142,21 @@ class SprayingOCRActivity :
|
|||||||
override fun adapter(): BasePagedAdapter<ItemItem> = adapter
|
override fun adapter(): BasePagedAdapter<ItemItem> = adapter
|
||||||
|
|
||||||
private fun showPhoto(path: String) {
|
private fun showPhoto(path: String) {
|
||||||
binding.content.setImageBitmap(BitmapFactory.decodeFile(path))
|
binding.content.doOnLayout {
|
||||||
|
val targetWidth = it.width.coerceAtLeast(1)
|
||||||
|
val targetHeight = it.height.coerceAtLeast(1)
|
||||||
|
imageDecodeExecutor.execute {
|
||||||
|
val bitmap = BitmapDecodeHelper.decodeSampledBitmap(path, targetWidth, targetHeight)
|
||||||
|
runOnUiThread {
|
||||||
|
if (isFinishing || isDestroyed) {
|
||||||
|
return@runOnUiThread
|
||||||
|
}
|
||||||
|
binding.content.setImageBitmap(bitmap)
|
||||||
restartResultCountdown(path)
|
restartResultCountdown(path)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun restartResultCountdown(path: String) {
|
private fun restartResultCountdown(path: String) {
|
||||||
resultCountdown?.cancel()
|
resultCountdown?.cancel()
|
||||||
|
|||||||
@ -2,14 +2,15 @@ package com.nova.brain.glass.ui
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.core.view.doOnLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.nova.brain.glass.R
|
import com.nova.brain.glass.R
|
||||||
import com.nova.brain.glass.databinding.ActivitySprayingResultBinding
|
import com.nova.brain.glass.databinding.ActivitySprayingResultBinding
|
||||||
|
import com.nova.brain.glass.helper.BitmapDecodeHelper
|
||||||
import com.nova.brain.glass.helper.OfflineCmdListener
|
import com.nova.brain.glass.helper.OfflineCmdListener
|
||||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||||
import com.nova.brain.glass.helper.SprayingPhotoManager
|
import com.nova.brain.glass.helper.SprayingPhotoManager
|
||||||
@ -25,6 +26,7 @@ import com.xuqm.base.common.LogHelper
|
|||||||
import com.xuqm.base.extensions.showMessage
|
import com.xuqm.base.extensions.showMessage
|
||||||
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
|
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.concurrent.Executors
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
class SprayingResultActivity :
|
class SprayingResultActivity :
|
||||||
@ -33,6 +35,7 @@ class SprayingResultActivity :
|
|||||||
override fun fullscreen(): Boolean = true
|
override fun fullscreen(): Boolean = true
|
||||||
|
|
||||||
override fun getRecyclerOrientation(): Int = RecyclerView.HORIZONTAL
|
override fun getRecyclerOrientation(): Int = RecyclerView.HORIZONTAL
|
||||||
|
private val imageDecodeExecutor = Executors.newSingleThreadExecutor()
|
||||||
private var status = true
|
private var status = true
|
||||||
private val manualResultLauncher =
|
private val manualResultLauncher =
|
||||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
@ -157,7 +160,7 @@ class SprayingResultActivity :
|
|||||||
super.initData()
|
super.initData()
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
intent.getStringExtra("path")?.apply {
|
intent.getStringExtra("path")?.apply {
|
||||||
binding.iv.setImageBitmap(BitmapFactory.decodeFile(this))
|
showResultImage(this)
|
||||||
setStatusImage()
|
setStatusImage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,4 +234,20 @@ class SprayingResultActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun adapter(): BasePagedAdapter<ItemItem> = adapter
|
override fun adapter(): BasePagedAdapter<ItemItem> = adapter
|
||||||
|
|
||||||
|
private fun showResultImage(path: String) {
|
||||||
|
binding.iv.doOnLayout {
|
||||||
|
val targetWidth = it.width.coerceAtLeast(1)
|
||||||
|
val targetHeight = it.height.coerceAtLeast(1)
|
||||||
|
imageDecodeExecutor.execute {
|
||||||
|
val bitmap = BitmapDecodeHelper.decodeSampledBitmap(path, targetWidth, targetHeight)
|
||||||
|
runOnUiThread {
|
||||||
|
if (isFinishing || isDestroyed) {
|
||||||
|
return@runOnUiThread
|
||||||
|
}
|
||||||
|
binding.iv.setImageBitmap(bitmap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户