Android Kotlin重复创建传感器数据文件时EExit错误的解决方法
问题修复方案
错误原因分析
你遇到的EExit错误,本质是Android文件系统缓存/媒体库同步延迟导致的误判:手动删除文件后,系统MediaStore或文件系统缓存未及时更新,当程序尝试创建同名文件时,系统误以为文件仍存在;另外依赖saveCounter自增生成文件名的逻辑,若未结合目录现有文件计数,也可能导致重复文件名冲突。
修复方案
以下是几种针对性的修复方法,按推荐优先级排序:
- 使用绝对唯一的文件名(最推荐):放弃依赖
saveCounter,改用时间戳生成文件名,确保每次创建的文件绝对唯一,彻底避免文件名冲突。 - 手动同步文件系统状态:创建文件前,强制检查文件实际存在状态,若系统缓存误判则手动刷新媒体库。
- 动态初始化saveCounter:启动时扫描目标目录,自动计算当前最大文件编号,确保
saveCounter从正确值开始自增。
完整修改代码(方案1实现)
import android.Manifest import android.content.pm.PackageManager import android.os.Bundle import android.os.Environment import android.widget.Button import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.io.File import java.text.SimpleDateFormat import java.util.* class MainActivity : AppCompatActivity() { private var isSaving = false private var currentFileName: String? = null private val coroutineScope = CoroutineScope(Dispatchers.IO) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setChart() checkFunction() val saveButton: Button = findViewById(R.id.btn_save) saveButton.setOnClickListener { if (isSaving) { isSaving = false saveButton.text = "Save Start" Toast.makeText(this, "已停止数据保存", Toast.LENGTH_SHORT).show() } else { isSaving = true saveButton.text = "Save Stop" if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1) } else { Toast.makeText(this, "已开始数据保存", Toast.LENGTH_SHORT).show() // 生成绝对唯一的文件名:时间戳+随机数 currentFileName = "Sensor_data_${System.currentTimeMillis()}_${Random().nextInt(1000)}.txt" coroutineScope.launch { while (isSaving) { saveSensorDataToFile() delay(1000) } } } } } } private fun saveSensorDataToFile() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && currentFileName != null ) { val root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val dir = File(root, "SensorData3") dir.mkdirs() val file = File(dir, currentFileName!!) // ThreadLocal解决SimpleDateFormat线程不安全问题 val sdf = ThreadLocal.withInitial { SimpleDateFormat("MM-dd HH:mm:ss", Locale.getDefault()) }.get() val currentDate = sdf.format(Date()) val data = "$currentDate, $pre_x, $acc_x, $acc_y, $acc_z\n" // 显式确认文件状态,避免缓存误判 if (!file.exists()) { file.createNewFile() } file.appendText(data) } else { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 0 ) } } private fun checkFunction() { val permissions = arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE ) if (permissions.any { ActivityCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }) { ActivityCompat.requestPermissions(this, permissions, 101) } } // 保留你的图表初始化逻辑 private fun setChart() { // 原图表代码实现 } // 保留你的传感器数据变量 private var pre_x = 0.0 private var acc_x = 0.0 private var acc_y = 0.0 private var acc_z = 0.0 }
额外优化建议
- 替换
GlobalScope为lifecycleScope(需依赖AndroidX lifecycle-runtime-ktx),避免内存泄漏 - 使用
ThreadLocal封装SimpleDateFormat,解决多线程下的线程安全问题 - 简化权限请求逻辑,去除冗余的条件判断
内容的提问来源于stack exchange,提问作者이건웅
相关产品推荐
相关产品推荐

