diff --git a/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt index 21207eb..9aa5bdd 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/InitActivity.kt @@ -14,7 +14,6 @@ import com.sw.dualscreen.ext.clickWithDebounce import com.sw.dualscreen.ext.invisible import com.sw.dualscreen.ext.visible import com.sw.dualscreen.objbox.FoodModule -import com.sw.dualscreen.utils.FaceDbImporter import com.sw.dualscreen.utils.FoodVectorTool import com.sw.dualscreen.utils.L import com.sw.dualscreen.utils.NetworkUtils @@ -23,10 +22,7 @@ import com.sw.dualscreen.viewmodel.BaseViewModel import com.sw.dualscreen.viewmodel.NetViewModelV2 import com.sw.plate.utils.AppUtil import com.sw.plate.utils.ToastUtils -import com.sw.plate.utils.arcface.faceserver.FaceServer -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext class InitActivity : BaseActivity() { companion object { @@ -69,28 +65,6 @@ class InitActivity : BaseActivity() { } showWaitingDialog("网络连接中...") checkNetworkTimer?.start() - -// val isSuccess = viewModel.checkEquipmentInfo() -// if (isSuccess) { -// goMainActivity() -// return -// } -// binding.imgQr.setImageBitmap( -// QRCodeUtil.generateQRCode( -// content = GlobalData.deviceId, -// size = 200 -// ) -// ) -// binding.initButton.setOnClickListener { -// viewModel.getDeviceToken() -// } - - lifecycleScope.launch { - withContext(Dispatchers.IO) { - FaceServer.getInstance().clearAllFaces() - loadTestDb() - } - } } override fun registerDataChange() { @@ -118,7 +92,6 @@ class InitActivity : BaseActivity() { } } } - checkCameraPermissionAndGo() } private fun goMainActivity() { @@ -264,24 +237,24 @@ class InitActivity : BaseActivity() { - private fun loadTestDb() { - // 从测试库导入人脸数据 - FaceDbImporter.importFromAssets(this, object : FaceDbImporter.ImportCallback { - public override fun onProgress(current: Int, total: Int) { - showWaitingDialog("导入人脸数据 " + current + "/" + total) - } - - public override fun onError(message: String?) { - hideWaitingDialog() - ToastUtils.showToast("离线数据导入失败:" + message) - } - - public override fun onComplete() { - hideWaitingDialog() - ToastUtils.showToast("离线数据导入成功") - // 后续流程会自动跳转 - } - }) - } +// private fun loadTestDb() { +// // 从测试库导入人脸数据 +// FaceDbImporter.importFromAssets(this, object : FaceDbImporter.ImportCallback { +// public override fun onProgress(current: Int, total: Int) { +// showWaitingDialog("导入人脸数据 " + current + "/" + total) +// } +// +// public override fun onError(message: String?) { +// hideWaitingDialog() +// ToastUtils.showToast("离线数据导入失败:" + message) +// } +// +// public override fun onComplete() { +// hideWaitingDialog() +// ToastUtils.showToast("离线数据导入成功") +// // 后续流程会自动跳转 +// } +// }) +// } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/activity/fragment/CollectFragment.kt b/app/src/main/java/com/sw/dualscreen/activity/fragment/CollectFragment.kt index 288c318..35e8957 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/fragment/CollectFragment.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/fragment/CollectFragment.kt @@ -34,6 +34,7 @@ import com.sw.dualscreen.utils.Debouncer import com.sw.dualscreen.utils.ImageUploader import com.sw.dualscreen.utils.ImageUtil import com.sw.plate.utils.ToastUtils +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import timber.log.Timber @@ -97,15 +98,15 @@ class CollectFragment : BaseFragment() { } - private val cameraCallback: (Uri) -> Unit = { uri -> + private val cameraCallback: (Uri) -> Unit = cameraCallback@{ uri -> try { val index = foodCollectionList.indexOfFirst { it.imageFile == null } if (index == -1) { ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据") settingActivity?.hideWaitingDialog() - rerurn@ cameraCallback + return@cameraCallback } - activity?.runOnUiThread { + activity?.lifecycleScope?.launch(Dispatchers.Main) { foodCollectionList[index].let { it.imageVector = null it.bitmap = null @@ -116,7 +117,7 @@ class CollectFragment : BaseFragment() { collectionAdapter.notifyItemChanged(index) } // settingActivity?.hideWaitingDialog() - activity?.lifecycleScope?.launch { + activity?.lifecycleScope?.launch(Dispatchers.IO) { ImageUtil.uriToBitmap(requireActivity(), uri)?.let { bitmap -> getImageVector(index, bitmap) } @@ -149,19 +150,16 @@ class CollectFragment : BaseFragment() { ) settingActivity?.log("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${file?.absolutePath}") - activity?.runOnUiThread { - foodCollectionList[index].let { - it.imageVector = imageVector - it.bitmap = null - it.isShowCamera = false - it.imageFile = file - } - collectionAdapter.notifyItemChanged(index) + foodCollectionList[index].let { + it.imageVector = imageVector + it.bitmap = null + it.isShowCamera = false + it.imageFile = file } + settingActivity?.hideWaitingDialog() if (bitmap.isRecycled.not()) { bitmap.recycle() } - settingActivity?.hideWaitingDialog() } @SuppressLint("NotifyDataSetChanged") @@ -171,19 +169,15 @@ class CollectFragment : BaseFragment() { ToastUtils.showToast("每次只允许保存${MAX_COUNT}条数据") return } + settingActivity?.showWaitingDialog("采集中……") - cameraUtils.takePhoto(cameraCallback) { errMsg -> + cameraUtils.takePhoto(succCallback = { uri -> + settingActivity?.lifecycleScope?.launch((Dispatchers.IO)) { + cameraCallback(uri) + } + }, failCallback = { errMsg -> settingActivity?.hideWaitingDialog() -// ToastUtils.showToast("拍照异常,请重新操作") -// if (cameraErrorCount >= 10) { -// ToastUtils.showToast("拍照异常,请重新操作") -// settingActivity?.log("拍照异常,请重新操作:$errMsg") -// cameraErrorCount = 0 -// return@takePhoto -// } -// cameraErrorCount++ -// takePhoto() - } + }) } private var cameraErrorCount = 0 diff --git a/app/src/main/java/com/sw/dualscreen/objbox/FoodModule.kt b/app/src/main/java/com/sw/dualscreen/objbox/FoodModule.kt index 3c1b1d1..9264267 100644 --- a/app/src/main/java/com/sw/dualscreen/objbox/FoodModule.kt +++ b/app/src/main/java/com/sw/dualscreen/objbox/FoodModule.kt @@ -153,7 +153,9 @@ object FoodModule { suspend fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 50): List { val startTime = System.currentTimeMillis() - val floatArray = bitmap2FloatArray(bitmap, false) + val floatArray = withContext(Dispatchers.IO) { + bitmap2FloatArray(bitmap, false) + } Timber.tag(TAG).d("bitmap2FloatArray,耗时:${System.currentTimeMillis() - startTime}") val nameScoreList = queryFoodNameScore(floatArray, queryCount) diff --git a/app/src/main/java/com/sw/dualscreen/utils/CameraUtils.kt b/app/src/main/java/com/sw/dualscreen/utils/CameraUtils.kt index c31865b..c802f16 100644 --- a/app/src/main/java/com/sw/dualscreen/utils/CameraUtils.kt +++ b/app/src/main/java/com/sw/dualscreen/utils/CameraUtils.kt @@ -34,7 +34,6 @@ class CameraUtils(private var activity: ComponentActivity) { photoCaptureHelper = PhotoCaptureHelper( context = activity, cameraController = cameraController!!, - onSuccess = {}, onError = { msg -> //toast(msg) failCallback?.invoke(msg) diff --git a/app/src/main/java/com/sw/dualscreen/utils/ImageUtil.kt b/app/src/main/java/com/sw/dualscreen/utils/ImageUtil.kt index 79e3325..607fd7d 100644 --- a/app/src/main/java/com/sw/dualscreen/utils/ImageUtil.kt +++ b/app/src/main/java/com/sw/dualscreen/utils/ImageUtil.kt @@ -15,17 +15,23 @@ object ImageUtil { fun uriToBitmap(context: Context, uri: Uri): Bitmap? { return try { - val options = BitmapFactory.Options() - //options.inSampleSize = 2; // 这会将图片的尺寸缩小到原来的1/2 - options.inJustDecodeBounds = false -// options.inPreferredConfig = Bitmap.Config.ARGB_8888 - options.inPreferredConfig = Bitmap.Config.RGB_565 + val options = BitmapFactory.Options().apply { + inJustDecodeBounds = true + } + // 先只读尺寸,计算合适的采样率 context.contentResolver.openInputStream(uri)?.use { stream -> BitmapFactory.decodeStream(stream, null, options) -// BitmapFactory.decodeStream(stream) + } + // 目标最长边不超过 800px,减少内存占用 + val maxDim = maxOf(options.outWidth, options.outHeight) + val sampleSize = (maxDim / 800).coerceAtLeast(1) + options.apply { + inJustDecodeBounds = false + inSampleSize = sampleSize + inPreferredConfig = Bitmap.Config.RGB_565 } context.contentResolver.openInputStream(uri)?.use { stream -> - BitmapFactory.decodeStream(stream) + BitmapFactory.decodeStream(stream, null, options) } } catch (e: Exception) { e.printStackTrace() diff --git a/app/src/main/java/com/sw/dualscreen/utils/PhotoCaptureHelper.kt b/app/src/main/java/com/sw/dualscreen/utils/PhotoCaptureHelper.kt index d91585c..f58d1f0 100644 --- a/app/src/main/java/com/sw/dualscreen/utils/PhotoCaptureHelper.kt +++ b/app/src/main/java/com/sw/dualscreen/utils/PhotoCaptureHelper.kt @@ -20,13 +20,8 @@ import java.io.File class PhotoCaptureHelper( private val context: Context, private val cameraController: CameraController, - private val onSuccess: (Uri) -> Unit = {}, private val onError: (String) -> Unit = {} ) { - companion object { - /** 临时测试开关:true 时跳过拍照,直接返回固定图片Uri */ - const val TEST_MODE = true - } private val callbackList: MutableList<(Uri) -> Unit> = mutableListOf() fun addSuccessCallback(callback:(Uri) -> Unit) { @@ -49,28 +44,6 @@ class PhotoCaptureHelper( fileNamePrefix: String = "IMG_", fileExtension: String = ".jpg" ) { - // TODO: 测试完成后删除此段代码,并将 TEST_MODE 置为 false - if (TEST_MODE) { - val testDir = context.externalCacheDir ?: context.cacheDir - val testFile = File(testDir, "test_photo_${System.currentTimeMillis()}.jpg") - if (!testFile.exists()) { - testFile.parentFile?.mkdirs() - val bitmap = android.graphics.Bitmap.createBitmap(480, 640, android.graphics.Bitmap.Config.ARGB_8888) - val canvas = android.graphics.Canvas(bitmap) - canvas.drawColor(0xFFCCCCCC.toInt()) - testFile.outputStream().use { fos -> - bitmap.compress(android.graphics.Bitmap.CompressFormat.JPEG, 95, fos) - } - bitmap.recycle() - } - val authority = "${context.packageName}.fileprovider" - val testUri = FileProvider.getUriForFile(context, authority, testFile) - Timber.d("测试模式:跳过拍照,返回 content://Uri: $testUri") - onSuccess(testUri) - callbackList.forEach { it(testUri) } - return - } - Timber.d("开始拍照采集") try { @@ -91,7 +64,6 @@ class PhotoCaptureHelper( override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { val photoUri = outputFileResults.savedUri ?: Uri.fromFile(photoFile) Timber.d("照片保存成功: $photoUri") - onSuccess(photoUri) callbackList.forEach { it(photoUri) }