You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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获取的目录/文件:

  1. 确保项目引入AndroidX DocumentFile依赖(若使用AndroidX):
implementation "androidx.documentfile:documentfile:1.0.1"
  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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:04:54