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

Flutter获取Android应用目录MP3文件并展示至ListView问题求助

问题分析与解决方案

核心问题

  1. 路径硬编码错误:代码中硬编码的目录是/storage/emulated/0/Android/data/com.example.cast/files,但你的实际应用包名是com.example.MyApp,路径不匹配导致读取到错误目录的文件。
  2. 文件名显示错误:ListView的title直接输出了整个allSongs列表,无法正确展示单个文件名。
  3. 同步目录遍历阻塞UI:使用listSync()同步遍历目录,可能导致UI卡顿。

修正步骤

1. 用官方API获取正确的应用专属目录

避免硬编码路径,使用path_provider插件获取系统推荐的应用专属外部存储目录,适配所有Android版本和设备。

  • 先在pubspec.yaml添加依赖:
dependencies:
  path_provider: ^2.0.15
  • 修改getFiles()方法,替换目录获取逻辑:
import 'package:path_provider/path_provider.dart'; // 导入插件

void getFiles() async {
  // 获取应用专属外部文件目录
  Directory? dir = await getExternalStorageDirectory();
  if (dir == null) {
    print("无法获取应用目录");
    return;
  }
  String mp3Path = dir.path;
  print(mp3Path);
  
  List<FileSystemEntity> _songs = [];
  
  try {
    // 异步遍历目录,避免阻塞UI
    await for (var entity in dir.list(recursive: true, followLinks: false)) {
      String path = entity.path;
      if (path.endsWith('.mp3')) {
        _songs.add(entity);
      }
    }
  } catch (e) {
    print("读取目录出错: $e");
  }
  
  print("找到MP3文件数量: ${_songs.length}");
  setState(() {
    files = _songs;
    allSongs = _songs;
  });
}

2. 修正ListView的文件名显示

使用path包的basename()方法从文件路径提取纯文件名,替换原有的列表输出:

  • 先导入path包:
import 'package:path/path.dart' as path;
  • 修改ListTile的title部分:
title: Text(
  path.basename(allSongs![index].path), // 提取单个文件名
  maxLines: 1,
  style: const TextStyle(
    color: Colors.white,
    fontWeight: FontWeight.w400,
  ),
),

3. 权限适配(可选)

  • Android 9及以下版本:需在AndroidManifest.xml添加存储权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  • Android 10及以上:应用专属目录无需额外权限,系统自动授权。

完整修正代码

import 'dart:io';
import 'package:cast/utilities/bottom_sheet_widget.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;

class MyAudioList extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyAudioList();
  }
}

class _MyAudioList extends State<MyAudioList> {
  var files;
  List<FileSystemEntity>? allSongs;

  void getFiles() async {
    Directory? dir = await getExternalStorageDirectory();
    if (dir == null) {
      print("无法获取应用专属目录");
      return;
    }
    String mp3Path = dir.path;
    print(mp3Path);

    List<FileSystemEntity> _songs = [];

    try {
      await for (var entity in dir.list(recursive: true, followLinks: false)) {
        String filePath = entity.path;
        if (filePath.endsWith('.mp3')) {
          _songs.add(entity);
        }
      }
    } catch (e) {
      print("读取目录错误: $e");
    }

    print("找到MP3文件数量: ${_songs.length}");
    setState(() {
      allSongs = _songs;
      files = _songs;
    });
  }

  @override
  void initState() {
    getFiles();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return RefreshIndicator(
      onRefresh: () async {
        getFiles();
      },
      child: Scaffold(
        body: allSongs == null
            ? const Center(
                child: Text(
                  '搜索中..',
                  style: TextStyle(color: Colors.white),
                ),
              )
            : allSongs!.isEmpty
                ? const Center(
                    child: Text(
                      '未找到MP3文件',
                      style: TextStyle(color: Colors.white),
                    ),
                  )
                : ListView.builder(
                    itemCount: allSongs!.length,
                    itemBuilder: (context, index) {
                      final song = allSongs![index];
                      return ListTile(
                        key: UniqueKey(),
                        leading: ClipRRect(
                          borderRadius: BorderRadius.circular(8),
                          child: Image.network(
                            "https://images.unsplash.com/photo-1541963463532-d68292c34b19?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8Ym9va3xlbnwwfHwwfHw%3D&w=1000&q=80",
                            width: 50,
                            height: 50,
                            fit: BoxFit.cover,
                          ),
                        ),
                        title: Text(
                          path.basename(song.path),
                          maxLines: 1,
                          style: const TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.w400,
                          ),
                        ),
                        subtitle: Text(
                          "publisher",
                          style: TextStyle(
                            color: Colors.grey[400]!,
                            fontSize: 13,
                          ),
                        ),
                        trailing: IconButton(
                          onPressed: () {},
                          icon: const Icon(Icons.more_vert, color: Colors.grey),
                        ),
                      );
                    },
                  ),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Digamber negi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:57:25