Home > Software engineering >  setState() or markNeedsBuild() called during build. during provider
setState() or markNeedsBuild() called during build. during provider

Time:01-14

i am trying to update the current track in the stream by using provider. but i am getting this error which is mention below

What i want to do is every time a new song is played i want to get that songs data and compare it to list of songs from which i can show that this particular song is getting played right now . no matter where that list is in the tree.

///// this is the class which is getting called by provider.

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

this is where i am trying to update it

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);
            },),
        ],
      ),
    ),
  );
       },
   );
   }
     }

this is error

    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'

CodePudding user response:

You call notifyListeners, which, among other things, calls setState on widgets that are listening to the event provider. This is a problem because you cannot call setState on a widget when the widget is in the middle of rebuilding.

This line calls the provider with listen set to true (which is the default), causing the framework to rebuild the UI even though it is currently being rebuild (since it is placed inside the builder), which is forbidden:

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

Move it outside the StreamBuilder´s builder and set listen to false like this if you want to get the data once for initialization:

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

Else put it inside didChangeDependecies

CodePudding user response:

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

Add this Line

  •  Tags:  
  • Related