【问题标题】:setState() or markNeedsBuild() called during build. during provider在构建期间调用 setState() 或 markNeedsBuild()。在提供者期间
【发布时间】:2022-01-13 10:10:09
【问题描述】:

我正在尝试使用提供程序更新流中的当前曲目。 但我收到了下面提到的这个错误

我想做的是每次播放一首新歌曲时,我都想获取该歌曲数据并将其与歌曲列表进行比较,我可以从中显示这首特定歌曲正在播放。无论该列表在树中的哪个位置。

///// 这是提供者调用的类。

import 'package:flutter/foundation.dart';
class MyCurrentTrack with ChangeNotifier{
  String _currentTrack = " ";
  String get currentTrack => _currentTrack;
  set currentTrack(String newValue){
    _currentTrack = newValue;
    notifyListeners();
  }
}

这是我要更新的地方

class MusicPlaeryerMini{
Widget musicPlayerMini(){
return StreamBuilder<PlayerState>(
  stream: SpotifySdk.subscribePlayerState(),
  builder: (BuildContext context, AsyncSnapshot<PlayerState> snapshot) {
    final currentTime = Provider.of<MyCurrentTrack>(context);//called the function here 
    var track = snapshot.data?.track;
    currentTrackImageUri = track?.imageUri;
    var playerState = snapshot.data;
    if(playerState != null){
      currentTime.currentTrack = playerState.track!.uri;// trying to update the value here 
      currentTrackTime = playerState.playbackPosition.toInt();
    }
    if (playerState == null || track == null ) {
      return Center(
          child: Container()
      );
    }

return
  Container(height: 70,
    decoration: const BoxDecoration( color: Colors.amberAccent,
        borderRadius: BorderRadius.all(Radius.circular(18))),
    width: screenWidth(context,dividedBy: 1.05),

    child: Padding(
      padding: const EdgeInsets.symmetric(horizontal: 10,vertical: 0),
      child: Row(
        children: [
          GestureDetector(onTap: (){
            Navigator.push (
              context,
              MaterialPageRoute (
                builder: (BuildContext context) =>  MusicPlayerFull(ispaused: playerState.isPaused,),
              ),
            );
          },
            child: Row(
              children: [
                SizedBox(width: 50,height: 50,
                    child: MusicPlayer().spotifyImageWidget(currentTrackImageUri!)),
                const SizedBox(width: 20),
                SizedBox(
                  width: screenWidth(context,dividedBy: 2.3 ,),
                  child: Column(crossAxisAlignment: CrossAxisAlignment.start,mainAxisAlignment: MainAxisAlignment.center,
                      children : [
                        SizedBox(width:screenWidth(context,dividedBy: 2.2),height: 18,
                            child:Text(track.name,overflow: TextOverflow.ellipsis,style: const TextStyle( fontWeight:FontWeight.bold ,fontSize: 16 ,color: Colors.blue ),
                            )
                        ),
                        Text(track.artist.name!,style:const TextStyle( fontWeight:FontWeight.bold ,fontSize: 16 ,color: Colors.blue ),overflow: TextOverflow.ellipsis)
                      ]),
                ),
              ],),),

          playerState.isPaused
              ? IconButton(
            icon: const Icon(Icons.play_arrow),
            onPressed: MusicPlayer().resume,
          )
              : IconButton(
            icon: const Icon(Icons.pause),
            onPressed: MusicPlayer().pause,
          ),
          IconButton(icon: const Icon(Icons.favorite ,color: Colors.blueGrey,)
            ,onPressed: (){
              MusicPlayer().addToLibrary(track.uri);
            },),
        ],
      ),
    ),
  );
       },
   );
   }
     }

这是错误

    The following assertion was thrown while dispatching notifications for MyCurrentTrack:
setState() or markNeedsBuild() called during build.

This _InheritedProviderScope<MyCurrentTrack?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope<MyCurrentTrack?>
  value: Instance of 'MyCurrentTrack'
  listening to value
The widget which was currently being built when the offending call was made was: StreamBuilder<PlayerState>
  dirty
  dependencies: [MediaQuery, _InheritedProviderScope<MyCurrentTrack?>]
  state: _StreamBuilderBaseState<PlayerState, AsyncSnapshot<PlayerState>>#4483f
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4261:11)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4276:6)
#2      _InheritedProviderScopeElement.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:570:5)
#3      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:308:24)
#4      MyCurrentTrack.currentTrack= (package:spotify_sdk_example/schedule.dart:12:5)
#5      MusicPlaeryerMini.musicPlayerMini.<anonymous closure> (package:spotify_sdk_example/widgets/musicPlayerMini.dart:20:23)
#6      StreamBuilder.build (package:flutter/src/widgets/async.dart:442:81)
#7      _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:124:48)
#8      StatefulElement.build (package:flutter/src/widgets/framework.dart:4705:27)
#9      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4588:15)
#10     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4763:11)
#11     Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)
#12     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2578:33)
#13     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#14     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:363:5)
#15     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1145:15)
#16     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1082:9)
#17     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)
#21     _invoke (dart:ui/hooks.dart:150:10)
#22     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#23     _drawFrame (dart:ui/hooks.dart:114:31)
(elided 3 frames from dart:async)
The MyCurrentTrack sending notification was: Instance of 'MyCurrentTrack'

【问题讨论】:

  • 我对@9​​87654324@ 不太熟悉,但我认为您最好在尝试更新小部件状态之前切换snapshot.connectionState 值。您可能正在寻找一个尚未加载的值。此外,检查snapshot.hasError 是否为true 可能是个好主意。 StreamBuilder API 下的示例可以让您很好地了解如何操作。

标签: flutter dart flutter-provider


【解决方案1】:

您调用 notifyListeners,其中包括在侦听事件提供程序的小部件上调用 setState。这是一个问题,因为当小部件处于重建过程中时,您无法在小部件上调用 setState。

这一行调用提供者时将listen设置为true(这是默认设置),导致框架重新构建UI,即使它当前正在重建(因为它被放置在构建器中),这是被禁止的:

 final currentTime = Provider.of<MyCurrentTrack>(context);

如果您想获取数据一次进行初始化,请将其移到 StreamBuilder 的构建器之外并设置为 false,如下所示:

final currentTime = Provider.of<MyCurrentTrack>(context, listen: false);

否则将其放在 didChangeDependecies 中

【讨论】:

  • 将它移到 StreamBuilder 之外不起作用,我也在 didChangeDependecies 内部尝试了这个,但它仍然显示相同的错误。这次在 didChangeDependencies 函数中。有没有其他方法可以从任何地方更新当前播放的曲目?
  • 你能分享你更新的代码吗?为什么不为 MusicPlayer 类扩展有状态或无状态小部件?
  • 我不知道什么是扩展有状态或无状态小部件。对我有帮助吗?
  • 不一定,但这是 Flutter 的核心基础,我建议你看看docs。
  • 我确实看过它,但我认为它不适合我。我必须更新流中 currentTrack 的值。但似乎无法找到一种方法来做到这一点
猜你喜欢
  • 2021-08-10
  • 2018-05-15
  • 1970-01-01
  • 2021-08-11
  • 2020-12-12
  • 2020-12-28
  • 2021-01-06
  • 2021-06-06
相关资源
最近更新 更多