Android Studio内部存储变量存读问题:加载按钮崩溃求助
问题描述
点击保存按钮将数据保存至MovingAndMoreAppData.txt,点击加载按钮读取数据时应用崩溃。目前仅能触发按钮点击事件,保存代码无法验证,尝试多种加载方式均无效。
相关代码
保存按钮逻辑
else if (xID == R.id.saveJobButton) { try { //to save data to a file FileOutputStream xFileOutput = openFileOutput("MovingAndMoreAppData.txt", MODE_PRIVATE); OutputStreamWriter xOutputWriter = new OutputStreamWriter(xFileOutput); xOutputWriter.write( xStartMiles); //integer variable from a EditText view //TODO after get xStartMiles working /*xStartTime + "," + xEndTime + "," + xEndDriveCounter + "," + xStartDriveCounter + "," + xEndMiles + "," + xTotalMiles + "," + xDriveTime1 + "," + xDriveTime2 + "," + xDriveTime3 + "," + xDriveTime4 + "," + xDriveTime5 + "," + xDriveTimeTotal + "," + xEndDriveTime1 + "," + xEndDriveTime2 + "," + xEndDriveTime3 + "," + xEndDriveTime4 + "," + xEndDriveTime5 + "," + xStartDriveTime1 + "," + xStartDriveTime2 + "," + xStartDriveTime3 + "," + xStartDriveTime4 + "," + xStartDriveTime5 + "," + xTotalTime); */ xOutputWriter.flush(); xOutputWriter.close(); Toast.makeText(TimeLogActivity.this, "Data Saved", Toast.LENGTH_SHORT).show(); } catch (IOException e) { Toast.makeText(TimeLogActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } }
加载按钮逻辑
//to load data from file else if (xID == R.id.loadJobButton) { Toast.makeText(TimeLogActivity.this, "button pressed", Toast.LENGTH_SHORT).show(); //need line below when loading data so it can display it //xStartMilesInput.setText(String.valueOf(50)); File xFileToRead = getApplicationContext().getFileStreamPath("MovingAndMoreAppData.txt"); String lineFromFile; if(xFileToRead.exists()) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("MovingAndMoreAppData.txt"))); while((lineFromFile = reader.readLine()) != null) { StringTokenizer tokens = new StringTokenizer(lineFromFile, ","); xStartMiles = Integer.parseInt(tokens.nextToken()); //set the EditText view to the integer value of the saved xStartMiles xStartMilesInput.setText(String.valueOf(xStartMiles)); } reader.close(); } catch (IOException e) { Toast.makeText(TimeLogActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } } }
LogCat错误日志
2023-12-13 11:56:51.855 19740-19740 AndroidRuntime com...andmoving404.movingandmoreapp E FATAL EXCEPTION: main Process: com.moreandmoving404.movingandmoreapp, PID: 19740 java.lang.NumberFormatException: For input string: "??" at java.lang.Integer.parseInt(Integer.java:604) at java.lang.Integer.parseInt(Integer.java:650) at com.moreandmoving404.movingandmoreapp.TimeLogActivity.onClick(TimeLogActivity.java:311) at android.view.View.performClick(View.java:7441) at android.view.View.performClickInternal(View.java:7418) at android.view.View.access$3700(View.java:835) at android.view.View$PerformClick.run(View.java:28676) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7839) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) 2023-12-13 11:56:57.449 19740-19753 System com...andmoving404.movingandmoreapp W A resource failed to call close.
问题分析与修复方案
核心问题
加载崩溃的直接原因是NumberFormatException,说明读取到的字符串无法转为整数。根源出在保存代码:
xOutputWriter.write(xStartMiles)调用的是Writer.write(int c)方法,这个方法会把整数当作ASCII码写入字符,而非写入数字的字符串形式。比如xStartMiles=123会被写成ASCII码对应的字符{,如果是其他数字可能生成乱码,导致读取时得到"??"这类无法解析的内容。
修复步骤
1. 修正保存代码
把整数转为字符串后再写入,同时为后续多数据保存预留分隔符(比如换行或逗号):
else if (xID == R.id.saveJobButton) { try { FileOutputStream xFileOutput = openFileOutput("MovingAndMoreAppData.txt", MODE_PRIVATE); OutputStreamWriter xOutputWriter = new OutputStreamWriter(xFileOutput); // 将整数转为字符串写入,加上换行符方便逐行读取 xOutputWriter.write(String.valueOf(xStartMiles) + "\n"); // 后续多数据保存时可以用逗号分隔,例如: // xOutputWriter.write(xStartMiles + "," + xStartTime + "," + xEndTime + "\n"); xOutputWriter.flush(); xOutputWriter.close(); Toast.makeText(TimeLogActivity.this, "Data Saved", Toast.LENGTH_SHORT).show(); } catch (IOException e) { Toast.makeText(TimeLogActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } }
2. 优化加载代码
- 添加异常处理,避免因解析失败或数据格式错误导致崩溃
- 使用
try-with-resources自动关闭流,避免资源泄漏 - 增加Token存在性判断,防止
NoSuchElementException
else if (xID == R.id.loadJobButton) { Toast.makeText(TimeLogActivity.this, "button pressed", Toast.LENGTH_SHORT).show(); File xFileToRead = getApplicationContext().getFileStreamPath("MovingAndMoreAppData.txt"); if(xFileToRead.exists()) { // 使用try-with-resources自动关闭BufferedReader try (BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("MovingAndMoreAppData.txt")))) { String lineFromFile; while((lineFromFile = reader.readLine()) != null) { // 先修剪字符串,去除空格和换行符 lineFromFile = lineFromFile.trim(); if(lineFromFile.isEmpty()) continue; StringTokenizer tokens = new StringTokenizer(lineFromFile, ","); // 先判断是否有可用的Token if(tokens.hasMoreTokens()){ try { xStartMiles = Integer.parseInt(tokens.nextToken().trim()); xStartMilesInput.setText(String.valueOf(xStartMiles)); } catch (NumberFormatException e) { Toast.makeText(TimeLogActivity.this, "数据格式错误:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } } } } catch (IOException e) { Toast.makeText(TimeLogActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(TimeLogActivity.this, "数据文件不存在", Toast.LENGTH_SHORT).show(); } }
后续扩展建议
当需要保存多组数据时,建议:
- 每条数据占一行,用逗号分隔各个字段
- 读取时按行解析,逐个字段转换类型
- 可以考虑使用JSON格式保存数据,比纯字符串分隔更易维护(比如用Gson库序列化对象)
内容的提问来源于stack exchange,提问作者Rob H
相关产品推荐
相关产品推荐

