Android Studio读取模拟器Download目录txt文件运行崩溃如何解决
崩溃原因及修复方案
核心崩溃原因
- 权限适配问题:Android 6.0以上读取外部存储需要动态申请权限,Android 10开始引入分区存储,直接访问
Environment.getExternalStorageDirectory()会被系统拦截,导致listFiles()返回null,遍历files.length时触发空指针崩溃 - Activity未注册:
ListaFilesActivity作为内部类定义在MainActivity中,未在AndroidManifest.xml注册,启动时会抛出Activity未找到异常 - 布局错误:
ListaFilesActivity复用了R.layout.activity_main,如果该布局没有id=ruta的TextView和id=listaFiles的ListView,findViewById返回null,调用相关方法时触发空指针 - 无空值校验:未对
listFiles()的返回值做非空判断,即使没有权限或者目录不存在也直接遍历,必然触发崩溃
分步修复方案
第一步:配置AndroidManifest.xml权限及Activity注册
<!-- 安卓13及以下通用存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 安卓13及以上媒体权限,适配公共目录读取 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- 如需读取所有类型文件可申请全文件访问权限,上架应用商店需提供用途说明 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <application ... <!-- 安卓10兼容配置,关闭分区存储限制 --> android:requestLegacyExternalStorage="true"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- 注册列表Activity,若后续拆成独立类,此处改为android:name=".ListaFilesActivity" --> <activity android:name=".MainActivity$ListaFilesActivity" /> </application>
第二步:MainActivity增加动态权限申请逻辑
public class MainActivity extends AppCompatActivity { Button Tomar_datos; // 权限申请回调 private ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult( new ActivityResultContracts.RequestPermission(), isGranted -> { if (isGranted) { startActivity(new Intent(MainActivity.this, ListaFilesActivity.class)); } else { Toast.makeText(this, "请授予存储权限后重试", Toast.LENGTH_SHORT).show(); } } ); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Tomar_datos = findViewById(R.id.Tomar_datos); } public void onClick(View view) { String permission; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { permission = Manifest.permission.READ_MEDIA_IMAGES; } else { permission = Manifest.permission.READ_EXTERNAL_STORAGE; } // 先判断是否已有权限 if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) { startActivity(new Intent(MainActivity.this, ListaFilesActivity.class)); } else { requestPermissionLauncher.launch(permission); } } // 内部类ListaFilesActivity保留,也可单独拆成独立Java文件 class ListaFilesActivity extends Activity { // 内部类逻辑见第三步修改 } }
第三步:修复ListaFilesActivity逻辑,增加空校验和txt过滤
首先建议新建独立的activity_lista_files.xml布局文件,包含id为ruta的TextView和id为listaFiles的ListView,然后修改Activity代码:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); // 替换为列表页专属布局 setContentView(R.layout.activity_lista_files); List<String> item = new ArrayList<>(); // 直接获取系统公共下载目录,不要自己拼接路径 File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File[] files = downloadDir.listFiles(); // 非空判断避免空指针 if (files != null) { for (File file : files) { // 只保留.txt后缀的文件 if (!file.isDirectory() && file.getName().toLowerCase().endsWith(".txt")) { item.add(file.getName()); } } } else { Toast.makeText(this, "无法读取下载目录,请检查权限配置", Toast.LENGTH_SHORT).show(); } TextView ruta = findViewById(R.id.ruta); ruta.setText(downloadDir.getAbsolutePath()); ListView lstOpciones = findViewById(R.id.listaFiles); ArrayAdapter<String> fileList = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, item); lstOpciones.setAdapter(fileList); // 原有点击事件逻辑可保留不变 lstOpciones.setOnItemClickListener((parent, view, position, id) -> { Intent data = new Intent(); data.putExtra("filename", item.get(position)); setResult(RESULT_OK, data); finish(); }); }
额外注意事项
- 优先将
ListaFilesActivity拆成独立的Java类,避免内部类带来的上下文泄漏、生命周期异常等问题 - 若需要适配Android 13以上读取非媒体类txt文件,可申请
MANAGE_EXTERNAL_STORAGE权限,该权限需要跳转系统设置页由用户手动开启 - 所有文件操作前都要做非空校验,不要直接假设返回的文件数组一定存在
内容的提问来源于stack exchange,提问作者Juanan
相关产品推荐
相关产品推荐

