使用ACTION_OPEN_DOCUMENT_TREE时Android Studio Java应用崩溃问题
Android 读取指定目录文件时应用崩溃问题
问题描述
手机sheet music目录下存储有anticipation_lyrics.txt文件,需实现将该文件内容读取至ID为@+id/editText的EditText中。修改代码后,点击“使用此文件夹”并授权后应用崩溃。
逻辑流程
- 用户点击按钮启动目录选择器
- 代码打开文档树选择器
- 用户选择目录
- 应用尝试打开目录内的
anticipation_lyrics.txt文件 - 代码检查文件是否存在
- 将文件内容读取至StringBuilder并设置到EditText中
怀疑崩溃位置
崩溃疑似发生在以下代码行,但无错误提示:
try (InputStream inputStream = getContentResolver().openInputStream(fileUri))
已配置权限
Manifest中已添加读取外部存储权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
完整原始代码
package com.enetapplications.displayfilecontent; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class DisplayFileContentActivity extends Activity { private static final int RQS_OPEN_DOCUMENT_TREE = 2; TextView textInfo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textInfo = findViewById(R.id.info); Button btnOpen = findViewById(R.id.opendocument); btnOpen.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); startActivityForResult(intent, RQS_OPEN_DOCUMENT_TREE); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // Check if the result is OK and if the request code matches the constant for opening a document tree if (resultCode == RESULT_OK && requestCode == RQS_OPEN_DOCUMENT_TREE) { Uri uriTree = data.getData(); // Retrieve the URI representing the selected directory // Get the EditText field. EditText editText = findViewById(R.id.editText); // Get the URI of the file "anticipation_lyrics.txt" within the chosen directory. Uri fileUri = Uri.withAppendedPath(uriTree, "anticipation_lyrics.txt"); // Open the file for reading and set its content in the EditText field try (InputStream inputStream = getContentResolver().openInputStream(fileUri)) { // Read the contents of the file into a string builder. StringBuilder stringBuilder = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line).append("\n"); } // Set the text of the EditText field to the contents of the file. editText.setText(stringBuilder.toString()); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "Error reading the file", Toast.LENGTH_SHORT).show(); // Notify the user about an error in file reading } } } }
问题原因及解决方案
错误原因
直接使用Uri.withAppendedPath(uriTree, "anticipation_lyrics.txt")拼接文档树URI的方式不正确,文档树URI的结构并非普通文件路径,无法通过简单拼接获取有效文件URI,导致openInputStream调用失败引发崩溃。此外,原代码未调用super.onActivityResult,也可能导致生命周期异常。
修改方案
使用DocumentFile类正确处理文档树URI,该类专门用于操作通过ACTION_OPEN_DOCUMENT_TREE获取的目录/文件:
- 确保项目引入AndroidX DocumentFile依赖(若使用AndroidX):
implementation "androidx.documentfile:documentfile:1.0.1"
- 修改
onActivityResult方法:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && requestCode == RQS_OPEN_DOCUMENT_TREE) { Uri uriTree = data.getData(); EditText editText = findViewById(R.id.editText); // 从文档树URI获取目录实例 DocumentFile directory = DocumentFile.fromTreeUri(this, uriTree); if (directory == null || !directory.isDirectory()) { Toast.makeText(this, "选择的目录无效", Toast.LENGTH_SHORT).show(); return; } // 查找目标文件 DocumentFile targetFile = directory.findFile("anticipation_lyrics.txt"); if (targetFile == null || !targetFile.isFile()) { Toast.makeText(this, "未找到anticipation_lyrics.txt文件", Toast.LENGTH_SHORT).show(); return; } // 读取文件内容 try (InputStream inputStream = getContentResolver().openInputStream(targetFile.getUri())) { StringBuilder stringBuilder = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line).append("\n"); } editText.setText(stringBuilder.toString()); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "读取文件失败", Toast.LENGTH_SHORT).show(); } // 可选:持久化权限,以便后续启动应用仍能访问该目录 getContentResolver().takePersistableUriPermission(uriTree, Intent.FLAG_GRANT_READ_URI_PERMISSION); } }
关键改进点
- 使用
DocumentFile.fromTreeUri正确解析文档树目录 - 通过
findFile方法安全查找目标文件,避免无效URI - 增加目录和文件有效性检查,提升容错性
- 调用
super.onActivityResult保证生命周期方法正常执行 - 可选添加持久化权限,实现长期访问
内容的提问来源于stack exchange,提问作者kiteandwindsurfer
相关产品推荐
相关产品推荐

