优化异常

This commit is contained in:
2026-01-13 19:08:56 +08:00
parent de0b6e994f
commit 8de09cf8c1
5 changed files with 155 additions and 105 deletions
@@ -371,13 +371,9 @@ class FoodCollectionActivity : ComponentActivity() {
// }
val goods = searchGoodsList[clickIndex]
val saveName = goods.goodsName + goods.goodsCode
box?.put(
Food(
name = saveName,
foodIdx = 0,
foodVector = imageVector
)
)
ObjectBox.boxStore.runInTx {
box?.put(Food(name = saveName, foodIdx = 0, foodVector = imageVector))
}
collectList[position].let {
// it.imageVector = imageVector
it.isFinish = true
@@ -158,7 +158,9 @@ class CollectSearchDialog(
}
val name = list[position].goodsName
val filterIdList = box?.all?.filter { it.name == name }?.map { it.id }
box?.removeByIds(filterIdList)
ObjectBox.boxStore.runInTx {
box?.removeByIds(filterIdList)
}
activity?.runOnUiThread {
Loading.dismiss()
//list.remove(list[position])
@@ -209,24 +211,24 @@ class CollectSearchDialog(
binding.root.hideKeyboard()
}
fun test() {
val goodsName = "多宝鱼,黑鱼(整条鱼),鸡腿肉"
activity?.searchGoodsInfoList(goodsName = goodsName) { items->
items.forEach { goods ->
box?.all?.filter {
it.name?.contains(goods.goodsName?:"-") == true
}?.forEach {
activity?.runOnUiThread {
activity?.toast(goods.goodsName)
}
it.name = goods.goodsName + goods.goodsCode
box?.put(it)
}
}
// activity?.runOnUiThread {
// activity?.toast("已保存")
// fun test() {
// val goodsName = "多宝鱼,黑鱼(整条鱼),鸡腿肉"
// activity?.searchGoodsInfoList(goodsName = goodsName) { items->
// items.forEach { goods ->
// box?.all?.filter {
// it.name?.contains(goods.goodsName?:"-") == true
// }?.forEach {
// activity?.runOnUiThread {
// activity?.toast(goods.goodsName)
// }
// it.name = goods.goodsName + goods.goodsCode
// box?.put(it)
// }
// }
}
}
//// activity?.runOnUiThread {
//// activity?.toast("已保存")
//// }
// }
// }
}
@@ -454,11 +454,11 @@ class GoodsStoreDialog(
Thread {
try {
val imageVector = FoodModule.bitmap2FloatArray(bitmap)
box?.put(
Food(
name = goods.goodsName + goods.goodsCode, foodIdx = 0, foodVector = imageVector
)
)
if (imageVector != null) {
ObjectBox.boxStore.runInTx {
box?.put(Food(name = goods.goodsName + goods.goodsCode, foodIdx = 0, foodVector = imageVector))
}
}
} catch (e: Exception) {
e.printStackTrace()
}
@@ -3,7 +3,8 @@ package com.sw.inbound.objbox
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.util.SparseLongArray
import android.renderscript.Element.DataType
import androidx.core.graphics.scale
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.sw.inbound.MyApp
@@ -22,6 +23,7 @@ import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
object FoodModule {
private lateinit var module_mobile: Module
@@ -31,6 +33,9 @@ object FoodModule {
private lateinit var classInfo: FoodClassInfo
private val NO_MEAN_RGB = floatArrayOf(0.0f, 0.0f, 0.0f)
private val NO_STD_RGB = floatArrayOf(1.0f, 1.0f, 1.0f)
// 1. 定义你的模型固定输入尺寸 (根据你的tflite模型修改,比如224x224)
private const val MODEL_INPUT_WIDTH = 300
private const val MODEL_INPUT_HEIGHT = 300
const val DEFAULT_FOOD_INDEX = -1
const val BAG_RATE = 0.05
@@ -48,49 +53,64 @@ object FoodModule {
}.start()
}
fun uri2FloatArray(uri: Uri): FloatArray? {
return MyApp.instance?.let { context ->
ImageUtil.uriToBitmap(context, uri)?.let {
bitmap2FloatArray(it)
// fun uri2FloatArray(uri: Uri): FloatArray? {
// return MyApp.instance?.let { context ->
// ImageUtil.uriToBitmap(context, uri)?.let {
// bitmap2FloatArray(it)
// }
// }
// }
fun bitmap2FloatArray(originBitmap: Bitmap): FloatArray? {
var rgb565Bitmap: Bitmap?=null
try {
val scaledBitmap = originBitmap.scale(MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT)
originBitmap.recycle()
rgb565Bitmap = scaledBitmap.copy(Bitmap.Config.RGB_565, false)
scaledBitmap.recycle()
val inputTensor = TensorImageUtils.bitmapToFloat32Tensor(
rgb565Bitmap,
NO_MEAN_RGB, // [0.485, 0.456, 0.406] TORCHVISION_NORM_MEAN_RGB
NO_STD_RGB // [0.229, 0.224, 0.225] TORCHVISION_NORM_STD_RGB
)
val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor()
return outputTensor.dataAsFloatArray
} catch (e: OutOfMemoryError) {
e.printStackTrace()
} finally {
if (rgb565Bitmap != null && rgb565Bitmap.isRecycled.not()) {
rgb565Bitmap.recycle()
}
//System.gc()
//System.runFinalization()
}
return null
}
fun bitmap2FloatArray(bitmap: Bitmap): FloatArray {
val inputTensor = TensorImageUtils.bitmapToFloat32Tensor(
bitmap,
NO_MEAN_RGB, // [0.485, 0.456, 0.406] TORCHVISION_NORM_MEAN_RGB
NO_STD_RGB // [0.229, 0.224, 0.225] TORCHVISION_NORM_STD_RGB
)
val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor()
// return floatArrayOf()
val floatArray = outputTensor.dataAsFloatArray
return floatArray
}
// fun queryFood(uri: Uri, queryCount: Int = 15): List<String>? {
// return uri2FloatArray(uri)?.let {
// queryFood(it, queryCount)
// }
// }
fun queryFood(uri: Uri, queryCount: Int = 15): List<String>? {
return uri2FloatArray(uri)?.let {
queryFood(it, queryCount)
}
}
// /**
// * 返回识别物品名称列表
// */
// fun queryFood(bitmap: Bitmap, queryCount: Int = 15): List<String> {
// val floatArray = bitmap2FloatArray(bitmap)
// return queryFood(floatArray, queryCount)
// }
/**
* 返回识别物品名称列表
*/
fun queryFood(bitmap: Bitmap, queryCount: Int = 15): List<String> {
val floatArray = bitmap2FloatArray(bitmap)
return queryFood(floatArray, queryCount)
}
// /**
// * 返回识别物品IdNameScore对象列表
// */
// fun queryFoodNameScore(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
// val floatArray = bitmap2FloatArray(bitmap)
// return queryFoodNameScore(floatArray, queryCount)
// }
/**
* 返回识别物品IdNameScore对象列表
*/
fun queryFoodNameScore(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
val floatArray = bitmap2FloatArray(bitmap)
return queryFoodNameScore(floatArray, queryCount)
}
fun queryFoodNameScore(floatArray: FloatArray, queryCount: Int = 15): List<IdNameScore> {
fun queryFoodNameScore(floatArray: FloatArray?, queryCount: Int = 15): List<IdNameScore> {
if (floatArray == null) return emptyList()
val query: Query<Food> =
box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build()
//查询比较分数
@@ -106,7 +126,7 @@ object FoodModule {
}
fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
val floatArray = bitmap2FloatArray(bitmap)
// return emptyList()
if (floatArray == null) return emptyList()
val nameScoreList = queryFoodNameScore(floatArray, queryCount)
if (nameScoreList.isEmpty()) {
return emptyList()
@@ -170,7 +190,9 @@ object FoodModule {
val classIdx = labelsList[index]
val foodName = foodMap["$classIdx"]
val array = floatList.toFloatArray()
box.put(Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX))
ObjectBox.boxStore.runInTx {
box.put(Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX))
}
}
action()
}
@@ -184,47 +206,75 @@ object FoodModule {
*
* 不可能反正SD
*/
fun copyAssetToCache(context: Context, fileName: String): String? {
// 此app的缓存目录 --> 会默认在 cache目录...,可以自己去看看哦
val cacheDir = context.getCacheDir()
if (!cacheDir.exists()) {
cacheDir.mkdirs() // TODO 如果没有缓存目录,就创建
}
val outPath = File(cacheDir, fileName) // TODO 创建输出的文件位置
if (outPath.exists()) {
outPath.delete() // TODO 如果该文件已经存在,就删掉
}
var `is`: InputStream? = null // 读取
var fos: FileOutputStream? = null // 写入
try {
// 创建文件,如果创建成功,就返回true
val res = outPath.createNewFile()
if (res) {
`is` = context.getAssets().open(fileName) // 拿到main/assets目录的输入流,用于读取字节
fos = FileOutputStream(outPath) // 读取出来的字节最终写到outPath
val buf = ByteArray(`is`.available()) // 缓存区
var byteCount: Int
// fun copyAssetToCache(context: Context, fileName: String): String? {
// // 此app的缓存目录 --> 会默认在 cache目录...,可以自己去看看哦
// val cacheDir = context.getCacheDir()
// if (!cacheDir.exists()) {
// cacheDir.mkdirs() // TODO 如果没有缓存目录,就创建
// }
// val outPath = File(cacheDir, fileName) // TODO 创建输出的文件位置
// if (outPath.exists()) {
// outPath.delete() // TODO 如果该文件已经存在,就删掉
// }
// var `is`: InputStream? = null // 读取
// var fos: FileOutputStream? = null // 写入
// try {
// // 创建文件,如果创建成功,就返回true
// val res = outPath.createNewFile()
// if (res) {
// `is` = context.getAssets().open(fileName) // 拿到main/assets目录的输入流,用于读取字节
// fos = FileOutputStream(outPath) // 读取出来的字节最终写到outPath
// val buf = ByteArray(`is`.available()) // 缓存区
// var byteCount: Int
//
// // 开始循环读取
// while ((`is`.read(buf).also { byteCount = it }) != -1) {
// fos.write(buf, 0, byteCount)
// }
// return outPath.getAbsolutePath()
// }
// } catch (e: IOException) {
// e.printStackTrace()
// } finally {
// try {
// // TODO 一定要记得关闭资源,为了不去性能的磨损
// fos?.flush()
// `is`?.close()
// fos?.close()
// } catch (e: IOException) {
// e.printStackTrace()
// }
// }
// return null
// }
// 开始循环读取
while ((`is`.read(buf).also { byteCount = it }) != -1) {
fos.write(buf, 0, byteCount)
}
return outPath.getAbsolutePath()
fun copyAssetToCache(context: Context, fileName: String): String? {
val cacheFile = File(context.cacheDir, fileName)
val buffer = ByteArray(8 * 1024)
var inputStream: InputStream? = null
var outputStream: FileOutputStream? = null
try {
inputStream = context.assets.open(fileName)
outputStream = FileOutputStream(cacheFile)
var byteCount: Int
while (inputStream.read(buffer).also { byteCount = it } != -1) {
outputStream.write(buffer, 0, byteCount)
}
outputStream.channel.force(true) // 强制物理落盘,比flush更彻底
return cacheFile.absolutePath
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
// TODO 一定要记得关闭资源,为了不去性能的磨损
fos?.flush()
`is`?.close()
fos?.close()
} catch (e: IOException) {
e.printStackTrace()
Timber.tag("FoodModule").d("文件拷贝失败 fileName=$fileName, error=${e.message}")
// 拷贝失败时删除残缺文件,避免下次读取到损坏文件
if (cacheFile.exists()) {
cacheFile.delete()
}
} finally {
outputStream?.close()
inputStream?.close()
}
return null
}
}
@@ -55,13 +55,15 @@ object ObjectBox {
private set
fun init(context: Context) {
// 优化:调大事务回收超时时间
System.setProperty("objectbox.finalizerTimeout", "30000");
// On Android make sure to pass a Context when building the Store.
boxStore = try {
MyObjectBox.builder()
.androidContext(context.applicationContext)
.build()
} catch (e: DbException) {
if (e.javaClass.equals(DbException::class.java) || e is FileCorruptException) {
if (e.javaClass == DbException::class.java || e is FileCorruptException) {
// Failed to build BoxStore due to database file issue, store message;
// checked in NoteListActivity to notify user.
dbExceptionMessage = e.toString()