Flutter UI freezes when clicked IconButton.

huangapple go评论70阅读模式
英文:

Flutter UI freezes when clicked IconButton

问题

我是新手学习Flutter/Dart。我正在尝试开发一个音乐播放器应用程序。问题是,当我的应用程序尝试从下载文件夹中检索所有MP3文件时,在模拟器上可以列出所有音频(MP3)文件,但当我在我的设备上安装APK时,按钮在按下时卡住了。

我可以做什么?

[模拟器:Android 13 Tiramisu]
<br>[设备:Android 11 R]

// 请求权限代码
requestPermission() async {
    // Web平台不支持权限方法。
    if (!kIsWeb) {
      bool permissionStatus = await _audioQuery.permissionsStatus();
      if (!permissionStatus) {
        await _audioQuery.permissionsRequest();
      }
      setState(() {});
    }
}

// 按钮代码
IconButton(
  icon: const Icon(Icons.menu_rounded, size: 30,), 
    onPressed: () {
      Navigator.push(context,MaterialPageRoute(builder: (context) =&gt; const Songs()));
},)
class _SongsState extends State&lt;Songs&gt; {

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(&#39;/&#39;).last,style:
                          const TextStyle(
                              fontSize: 21
                          ),),
                          leading: IconButton(onPressed: () {
                            Navigator.push(context,MaterialPageRoute(
                                builder: (context) =&gt; music_player(selectedSong: getSongList()[1],selectedIndex:index)
                            ));
                          },
                              icon: const Icon(Icons.play_circle,size: 30,)),
                        

  // 减少代码以适应SO问题,已删除所有大括号

  // 用于检索所有MP3的函数
  List getSongList(){

    Directory dir = Directory(&#39;/storage/emulated/0/Download/&#39;);
    String mp3Path = dir.toString();

    List&lt;FileSystemEntity&gt; _files;
    List&lt;FileSystemEntity&gt; _songs = [];
    List&lt;String&gt; _songpaths = [];
    _files = dir.listSync(recursive: true, followLinks: false);

    for(FileSystemEntity entity in _files) {
      String path = entity.path;
      if(path.endsWith(&#39;.mp3&#39;)) {
        _songs.add(entity);
        _songpaths.add(path);
      }
    }
    return [_songs,_songpaths];
  }

}

Flutter UI freezes when clicked IconButton.

英文:

I am new to flutter/dart. I am trying to develop a Music Player application.
Problem is when my application trying to retrieve all mp3 files from downloads folder.

It lists all audio(mp3) files on emulator, but when I installed APK on my device the button is stuck when pressed.

What can I do ?

[Emulator : Android 13 Tiramisu]
<br>[Device: Android 11 R]

//requesting permission code
requestPermission() async {
    // Web platform don&#39;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) =&gt; const Songs()));
},)
class _SongsState extends State&lt;Songs&gt; {

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(&#39;/&#39;).last,style:
                          const TextStyle(
                              fontSize: 21
                          ),),
                          leading: IconButton(onPressed: (){
                            Navigator.push(context,MaterialPageRoute(
                                builder: (context) =&gt; 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&#39;s
  List getSongList(){

    Directory dir = Directory(&#39;/storage/emulated/0/Download/&#39;);
    String mp3Path = dir.toString();

    List&lt;FileSystemEntity&gt; _files;
    List&lt;FileSystemEntity&gt; _songs = [];
    List&lt;String&gt; _songpaths = [];
    _files = dir.listSync(recursive: true, followLinks: false);

    for(FileSystemEntity entity in _files) {
      String path = entity.path;
      if(path.endsWith(&#39;.mp3&#39;)) {
        _songs.add(entity);
        _songpaths.add(path);
      }
    }
    return [_songs,_songpaths];
  }

}

Flutter UI freezes when clicked IconButton.

答案1

得分: 1

以下是代码部分的翻译:

基本问题是您试图在同步的`build`方法中获取音频文件列表。

您需要将其作为异步任务完成。类似这样的方式将起作用...

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();
    _fetchSongsAsync();
  }

  Future<void> _fetchSongsAsync() 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,
                              )));
                    }),
              ),
            ],
          );
        }),
      ),
    );
  }
}

希望这有助于您理解代码。如果您有任何其他问题,请随时提出。

英文:

Basic problem is you are trying to get list of audio files in build method in sync.

You need to do it as async task. Something like this would work...

class Songs extends StatefulWidget {
  const Songs({super.key});
  @override
  State&lt;StatefulWidget&gt; createState() =&gt; _SongsState();
}

class _SongsState extends State&lt;Songs&gt; {
  List&lt;FileSystemEntity&gt;? songs;
  List&lt;String&gt;? songpaths;

  StreamSubscription? _fetchSongs;

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

  Future&lt;void&gt; _fetchSongsAsyc() async {
    Directory dir = Directory(&#39;/storage/emulated/0/Download/&#39;);
    String mp3Path = dir.toString();

    List&lt;FileSystemEntity&gt; files;
    songs = [];
    songpaths = [];
    _fetchSongs = dir.list(recursive: true, followLinks: false).listen(
      (entity) {
        String path = entity.path;
        if (path.endsWith(&#39;.mp3&#39;)) {
          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(&#39;/&#39;).last,
                            style: const TextStyle(fontSize: 21),
                          ),
                          leading: IconButton(
                              onPressed: () {
                                Navigator.push(context,
                                    MaterialPageRoute(builder: (context) {
                                  Navigator.push(
                                      context,
                                      MaterialPageRoute(
                                          builder: (context) =&gt; music_player(
                                              selectedSong: songpaths,
                                              selectedIndex: index)));
                                }));
                              },
                              icon: const Icon(
                                Icons.play_circle,
                                size: 30,
                              )));
                    }),
              ),
            ],
          );
        }),
      ),
    );
  }
}

答案2

得分: 1

尝试使用以下代码获取音乐列表:

void getFiles() async { //异步函数,用于获取文件列表
  List<StorageInfo> storageInfo = await PathProviderEx.getStorageInfo();
  var root = storageInfo[0].rootDir; //获取根目录,storageInfo[1] 用于SD卡,获取根目录
  var fm = FileManager(root: Directory(root)); //
  files = await fm.filesTree( 
    excludedPaths: ["/storage/emulated/0/Android"],
    extensions: ["mp3"] //可选项,用于筛选文件,仅列出mp3文件
  );
  setState(() {}); //更新UI
}

然后用以下代码显示音乐列表:

files == null ? Text("正在搜索文件") :
   ListView.builder(  //如果文件/文件夹列表已获取,则在此处显示
      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: () {
                    // 在此处添加播放/推送代码
                 },
              )  
            );
      }
   );

请参考这篇文章,也可以使用这个获取更多功能。

英文:

Try this to get music list

void getFiles() async { //asyn function to get list of files
List&lt;StorageInfo&gt; 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: [&quot;/storage/emulated/0/Android&quot;],
extensions: [&quot;mp3&quot;] //optional, to filter files, list only mp3 files
);
setState(() {}); //update the UI
}  

Then to show music list

files == null? Text(&quot;Searching Files&quot;):
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(&#39;/&#39;).last),
leading: Icon(Icons.audiotrack),
trailing: Icon(Icons.play_arrow, color: Colors.redAccent,),
onTap: (){
// you can add Play/push code over here
},
)  

Kindly check this article
Also you can use this package for more features

huangapple
  • 本文由 发表于 2023年3月1日 14:51:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75600378.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定