如果我在我的 ListView 中显示超过 10 个声音,Flutter just_audio 包会抛出 null 异常

Flutter just_audio package throws null exception if I show more than 10 sounds in my ListView

我正在尝试构建一个简单的应用程序来播放资产文件夹中的音频文件。

我正在使用 Stream Builder return 为每个声音制作一张卡片以显示暂停和播放图标。但奇怪的是,当我在声音模型中添加超过 10 个声音时,我的应用程序会抛出一个空错误。

这是我的声音模型class:

class CoughViewModel extends ChangeNotifier{

  final List<SoundModel> _soundsList = [
    SoundModel(soundIcon: 'assets/vectors/death_bed.svg', soundName: 'DEATH BED', soundPath: 'assets/sounds/cough_sounds/death_bed.mp3'),
  ];

  List<SoundModel> get soundsList => _soundsList;
}

这是我用来显示声卡的代码:

    Expanded(
      child: ListView.builder(
          physics: const BouncingScrollPhysics(),
          itemCount: soundModel.length,
          itemBuilder: (BuildContext context,int index){
          return SoundCard(soundTitle: soundModel[index].soundName,soundPath: soundModel[index].soundPath,cardPicture: soundModel[index].soundIcon,);
      }),
    ),

这是我的流生成器​​:

return StreamBuilder<PlayerState>(
      stream: player.playerStateStream,
      builder: (context, snapshot) {
        print("STATEOFPLAYER : ${player.playerStateStream}");
        final playerState = snapshot.data;
        if(snapshot.hasData){
          return _cardReturner(playerState!);
        }
        else{
          return const CircularProgressIndicator(
            color: MyColors.color3,
          );
        }
      },
    );

这是我的小部件 returner 函数:

  Widget _cardReturner(PlayerState playerState) {
    final processingState = playerState.processingState;
    if (player.playing != true) {
      return soundCard(isPlaying: false);
    } else if (processingState != ProcessingState.completed) {
      return soundCard(isPlaying: true);
    } else {
      return soundCard(isPlaying: false);
    }
  }

由于某些奇怪的原因,当模型中的声音数量增加到 11

时,我的 player.playerStateStream 的 playerState 变为空

如果我手动将 ListView.builder 的 itemCount 设置为 10,则该应用程序可以正常运行。但是一旦数量超过我就会得到一个例外

此外这是我的声卡代码

class SoundCard extends StatefulWidget {
  final String? cardPicture;
  final String soundTitle;
  final String soundPath;

  const SoundCard({Key? key,this.cardPicture,required this.soundTitle,required this.soundPath}) : super(key: key);

  @override
  _SoundCardState createState() => _SoundCardState();
}

class _SoundCardState extends State<SoundCard> {
  final player = AudioPlayer();
  final Icon playIcon = const Icon(
    Icons.play_arrow,
    color: MyColors.color3,
  );
  final Icon pauseIcon = const Icon(
    Icons.pause,
    color: MyColors.color3,
  );

  final String playString = 'TAP TO PLAY';
  final String pauseString = 'TAP TO PAUSE';

  @override
  void dispose() {
    player.dispose();
    super.dispose();
  }

  @override
  void initState() {
    player.setAsset(widget.soundPath);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    ScreenUtil.setContext(context);
    return StreamBuilder<PlayerState>(
      stream: player.playerStateStream,
      builder: (context, snapshot) {
        print("STATEOFPLAYER : ${player.playerStateStream}");
        final playerState = snapshot.data;
        if(snapshot.hasData){
          return _cardReturner(playerState!);
        }
        else{
          return const CircularProgressIndicator(
            color: MyColors.color3,
          );
        }
      },
    );
  }

  Widget _cardReturner(PlayerState playerState) {
    final processingState = playerState.processingState;
    if (player.playing != true) {
      return soundCard(isPlaying: false);
    } else if (processingState != ProcessingState.completed) {
      return soundCard(isPlaying: true);
    } else {
      return soundCard(isPlaying: false);
    }
  }

  Widget soundCard({required bool isPlaying}) {
    return Container(
      margin: EdgeInsets.only(left:25.w,right: 25.w,top: 10.h,bottom: 10.h),
      decoration: BoxDecoration(
          color: MyColors.color2,
          borderRadius: BorderRadius.all(Radius.circular(10.r))),
      child: GestureDetector(
        onTap: () async {
          if (isPlaying) {
            player.stop();
          } else {
            player.setAsset(widget.soundPath);
            player.play();
          }
        },
        child: ListTile(
          leading: CircleAvatar(
            child: SvgPicture.asset(
              widget.cardPicture??'assets/vectors/sound_icon_cough.svg',
              height: 30.h,
            ),
            backgroundColor: MyColors.color1,
          ),
          title: Text(
            widget.soundTitle,
            style: MyTextStyles.bold15.copyWith(color: MyColors.color3),
          ),
          subtitle: Text(
            isPlaying ? pauseString : playString,
            style: MyTextStyles.medium15.copyWith(color: MyColors.color1),
          ),
          trailing: isPlaying ? pauseIcon : playIcon,
        ),
      ),
    );
  }
}

堆栈跟踪

flutter: STATEOFPLAYER : Instance of 'BehaviorSubject<PlayerState>'

======== Exception caught by widgets library =======================================================
The following _CastError was thrown building StreamBuilder<PlayerState>(dirty, state: _StreamBuilderBaseState<PlayerState, AsyncSnapshot<PlayerState>>#075ca):
Null check operator used on a null value

The relevant error-causing widget was: 
  StreamBuilder<PlayerState> StreamBuilder:file:///Users/junaidtariq/Documents/Documents/AndroidStudioProjects/the_hoax_flu/lib/global_widgets.dart:141:12
When the exception was thrown, this was the stack: 
#0      Element.widget (package:flutter/src/widgets/framework.dart:3203:31)
#1      debugCheckHasMediaQuery.<anonymous closure> (package:flutter/src/widgets/debug.dart:229:17)
#2      debugCheckHasMediaQuery (package:flutter/src/widgets/debug.dart:245:4)
#3      MediaQuery.of (package:flutter/src/widgets/media_query.dart:859:12)
#4      ScreenUtil.screenWidth (package:flutter_screenutil/screen_util.dart:69:51)
#5      ScreenUtil.scaleWidth (package:flutter_screenutil/screen_util.dart:88:28)
#6      ScreenUtil.setWidth (package:flutter_screenutil/screen_util.dart:101:41)
#7      SizeExtension.w (package:flutter_screenutil/size_extension.dart:5:32)
#8      _SoundCardState.soundCard (package:the_hoax_flu/global_widgets.dart:171:39)
#9      _SoundCardState._cardReturner (package:the_hoax_flu/global_widgets.dart:161:14)
#10     _SoundCardState.build.<anonymous closure> (package:the_hoax_flu/global_widgets.dart:147:18)
#11     StreamBuilder.build (package:flutter/src/widgets/async.dart:442:81)
#12     _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:124:48)
#13     StatefulElement.build (package:flutter/src/widgets/framework.dart:4870:27)
#14     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4754:15)
#15     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4928:11)
#16     Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#17     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2659:19)
#18     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#19     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:363:5)
#20     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
#21     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1081:9)
#22     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:995:5)
#26     _invoke (dart:ui/hooks.dart:151:10)
#27     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:308:5)
#28     _drawFrame (dart:ui/hooks.dart:115:31)
(elided 3 frames from dart:async)
====================================================================================================

我必须在最后期限前将此应用交付给客户。任何帮助将不胜感激 谢谢

您在呼叫 25.w 时访问 .w 分机。这仅在 ScreenUtil 中的上下文是最新的时才有效,它不适用于过时的上下文(来自上次构建)。

StreamBuilderbuild 回调独立于您的 Widgets build 函数进行更新。

StreamBuilder 构建函数被更频繁地调用。因此,您必须再次调用 ScreenUtil.setContext(context); 来更新 BuildContext。

  @override
  Widget build(BuildContext context) {
    ScreenUtil.setContext(context);
    return StreamBuilder<PlayerState>(
      stream: player.playerStateStream,
      builder: (context, snapshot) {

        // Update context
        ScreenUtil.setContext(context);

        print("STATEOFPLAYER : ${player.playerStateStream}");
        final playerState = snapshot.data;
        if (snapshot.hasData){
          return _cardReturner(playerState!);
        } else {
          return const CircularProgressIndicator(
            color: MyColors.color3,
          );
        }
      },
    );
  }