我是 flutter/dart 的新手。我正在尝试开发音乐播放器应用程序。 问题是当我的应用程序试图从下载文件夹中检索所有 mp3 文件时。
它列出了模拟器上的所有音频(mp3)文件,但是当我在我的设备上安装 APK 时,按钮在按下时卡住了。
我能做什么?
[模拟器:Android 13提拉米苏]
[设备:Android 11 R]
//requesting permission code
requestPermission() async {
// Web platform don't support permissions methods.
if (!kIsWeb) {
bool permissionStatus = await _audioQuery.permissionsStatus();
if (!permissionStatus) {
await _audioQuery.permissionsRequest();
}
setState(() {});
}
}
//Button code
IconButton(
icon: const Icon(Icons.menu_rounded, size: 30,),
onPressed: () {
Navigator.push(context,MaterialPageRoute(builder: (context) => const Songs()));
},)
class _SongsState extends State<Songs> {
body: SafeArea(
minimum: const EdgeInsets.fromLTRB(5, 10, 5, 5),
child: Column(
children: [
Expanded(
child:ListView.builder(
itemCount: getSongList()[0].length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(getSongList()[1][index].split('/').last,style:
const TextStyle(
fontSize: 21
),),
leading: IconButton(onPressed: (){
Navigator.push(context,MaterialPageRoute(
builder: (context) => music_player(selectedSong: getSongList()[1],selectedIndex:index)
));
},
icon: const Icon(Icons.play_circle,size: 30,)),
// Removed all brackets to reduce code for SO question
// function to retrieve all mp3's
List getSongList(){
Directory dir = Directory('/storage/emulated/0/Download/');
String mp3Path = dir.toString();
List<FileSystemEntity> _files;
List<FileSystemEntity> _songs = [];
List<String> _songpaths = [];
_files = dir.listSync(recursive: true, followLinks: false);
for(FileSystemEntity entity in _files) {
String path = entity.path;
if(path.endsWith('.mp3')) {
_songs.add(entity);
_songpaths.add(path);
}
}
return [_songs,_songpaths];
}
}
同意您的设备。当您在模拟器上运行您的应用程序时,它正在您的改进机器上运行,该机器具有对存档结构的完整归纳。然而,当你在一个真正的装置上运行你的应用程序时,它可能不会获得下载信封中记录的重要同意。
要解决这个问题,您需要在运行时请求客户端的关键同意。您最近执行了一个 requestPermission() 方法,该方法真正查看同意状态并在未获得批准时出售批准。在任何情况下,当应用程序未在 Web 平台上运行时,您可能会调用此方法。这表明 permissionsRequest() 过程没有被移向这个装置。
要解决此问题,您可以取消对 Web 阶段的检查,并在应用程序启动时可靠地调用 requestPermission() 方法。您可以以同样的方式在尝试获取记录之前添加检查是否已放弃同意。这是您的代码的一个充满活力的变体,应该可以工作:
class _SongsState extends State<Songs> {
bool _isPermissionGranted = false;
@override
void initState() {
super.initState();
requestPermission();
}
requestPermission() async {
bool permissionStatus = await _audioQuery.permissionsStatus();
if (!permissionStatus) {
await _audioQuery.permissionsRequest();
}
setState(() {
_isPermissionGranted = permissionStatus;
});
}
List getSongList() {
if (!_isPermissionGranted) {
// Permission not granted, return empty lists
return [[], []];
}
Directory dir = Directory('/storage/emulated/0/Download/');
String mp3Path = dir.toString();
List<FileSystemEntity> _files;
List<FileSystemEntity> _songs = [];
List<String> _songpaths = [];
_files = dir.listSync(recursive: true, followLinks: false);
for (FileSystemEntity entity in _files) {
String path = entity.path;
if (path.endsWith('.mp3')) {
_songs.add(entity);
_songpaths.add(path);
}
}
return [_songs, _songpaths];
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
minimum: const EdgeInsets.fromLTRB(5, 10, 5, 5),
child: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: getSongList()[0].length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
getSongList()[1][index].split('/').last,
style: const TextStyle(fontSize: 21),
),
leading: IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
music_player(selectedSong: getSongList()[1], selectedIndex: index),
),
);
},
icon: const Icon(Icons.play_circle, size: 30),
),
);
},
),
),
],
),
),
);
}
}
// check it out if you need any help let me know I am available
基本问题是您正在尝试同步构建方法中的音频文件列表。
你需要把它作为异步任务来做。像这样的东西会起作用......
class Songs extends StatefulWidget {
const Songs({super.key});
@override
State<StatefulWidget> createState() => _SongsState();
}
class _SongsState extends State<Songs> {
List<FileSystemEntity>? songs;
List<String>? songpaths;
StreamSubscription? _fetchSongs;
@override
void initState() {
super.initState();
_fetchSongsAsyc();
}
Future<void> _fetchSongsAsyc() async {
Directory dir = Directory('/storage/emulated/0/Download/');
String mp3Path = dir.toString();
List<FileSystemEntity> files;
songs = [];
songpaths = [];
_fetchSongs = dir.list(recursive: true, followLinks: false).listen(
(entity) {
String path = entity.path;
if (path.endsWith('.mp3')) {
songs?.add(entity);
songpaths?.add(path);
}
},
onDone: () {
_fetchSongs = null;
setState(() {});
},
);
}
@override
void dispose() {
_fetchSongs?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
minimum: const EdgeInsets.fromLTRB(5, 10, 5, 5),
child: Builder(builder: (context) {
if (songs == null) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Column(
children: [
Expanded(
child: ListView.builder(
itemCount: songs?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
songpaths![index].split('/').last,
style: const TextStyle(fontSize: 21),
),
leading: IconButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => music_player(
selectedSong: songpaths,
selectedIndex: index)));
}));
},
icon: const Icon(
Icons.play_circle,
size: 30,
)));
}),
),
],
);
}),
),
);
}
}
问题可能是由于您的模拟器和您的物理设备之间的文件系统结构或权限不同。您可以尝试使用
getExternalStorageDirectories
方法以与设备无关的方式访问音乐文件并添加异步。使用以下示例修改 getSongList()
函数:
import 'package:path_provider/path_provider.dart';
Future<List<List<String>>> getSongList() async {
List<FileSystemEntity> _songs = [];
List<String> _songpaths = [];
// Get list of external storage directories
List<Directory> storageDirectories = await getExternalStorageDirectories();
// Search for mp3 files in each directory
for (Directory dir in storageDirectories) {
String mp3Path = dir.path + '/Download';
Directory mp3Directory = Directory(mp3Path);
if (mp3Directory.existsSync()) {
List<FileSystemEntity> files = mp3Directory.listSync(recursive: true, followLinks: false);
for (FileSystemEntity entity in files) {
String path = entity.path;
if (path.endsWith('.mp3')) {
_songs.add(entity);
_songpaths.add(path);
}
}
}
}
return [_songs.map((e) => e.path).toList(), _songpaths];
}
试试这个来获取音乐列表
void getFiles() async { //asyn function to get list of files
List<StorageInfo> storageInfo = await PathProviderEx.getStorageInfo();
var root = storageInfo[0].rootDir; //storageInfo[1] for SD card, geting the root directory
var fm = FileManager(root: Directory(root)); //
files = await fm.filesTree(
excludedPaths: ["/storage/emulated/0/Android"],
extensions: ["mp3"] //optional, to filter files, list only mp3 files
);
setState(() {}); //update the UI
}
然后显示音乐列表
files == null? Text("Searching Files"):
ListView.builder( //if file/folder list is grabbed, then show here
itemCount: files?.length ?? 0,
itemBuilder: (context, index) {
return Card(
child:ListTile(
title: Text(files[index].path.split('/').last),
leading: Icon(Icons.audiotrack),
trailing: Icon(Icons.play_arrow, color: Colors.redAccent,),
onTap: (){
// you can add Play/push code over here
},
)