1

So, I am trying to display text from my void in other script file. I am not getting any errors, but I do get some messages instead of the text displayed. (Closure: (dynamic) => void from Function "rannn":. Tasks)

Any one can help me how to fix this issue so it will display the text?

Here is my code

class TaskData extends ChangeNotifier {
  List<Task> _tasks = [
    Task(name: "Task one"),
    Task(name: "Task two"),
    Task(name: "Task three"),
  ];

  UnmodifiableListView<Task> get tasks {
    return UnmodifiableListView(_tasks);
  }

  void rannn(String) async {
    var randomItem = (_tasks.toList()..shuffle()).first.name;
    print(randomItem);
    //notifyListeners();
  }

enter code here

Widget build(BuildContext context) => Container(
        color: Colors.transparent,
        child: Scaffold(
          //backgroundColor: Colors.transparent,
          backgroundColor: Colors.blue,
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                //SizedBox(height: 10),
                Text(
                  "${Provider.of<TaskData>(context).rannn} Tasks",
                ),
                //SizedBox(height: 10),//puts empty box to space things out
                buildTimer(),
                //const SizedBox(height: 10),
                buildButtons(),
              ],
            ),
          ),
        ),
      );

Thank you so much!

Added code of timer

class SecondRoute extends StatefulWidget {
  @override
  CustomMainPageState createState() => CustomMainPageState();
}

class CustomMainPageState extends State<SecondRoute> {
      static const maxSeconds = 5;
      int seconds = maxSeconds;
      Timer? timer;
    
      void resetTimer() => setState(() => seconds = maxSeconds);
    
      void startTimer({bool reset = true}) {
        if (reset) {
          resetTimer();
        }
        timer = Timer.periodic(Duration(seconds: 1), (_) {
          //add here instead seconds say minutes/miliseconds
          if (!mounted) // Putting this line of code with return under, fixed my issue i been having about mounted
            return;
          else if (seconds > 0) {
            setState(() => seconds--);
          } else {
            stopTimer(reset: false);
          }
        });
      }
    
      void stopTimer({bool reset = true}) {
        if (reset == mounted) {
          resetTimer();
        }
        setState(() => timer?.cancel());
      }
    
      Widget build(BuildContext context) => Container(
            color: Colors.transparent,
            child: Scaffold(
              //backgroundColor: Colors.transparent,
              backgroundColor: Colors.blue,
              body: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    FutureBuilder(
                      future: Provider.of<TaskData>(context).rann(),
                      builder: (context, snapshot) {
                        return Text(
                          "${snapshot.data}",
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: 35,
                              fontWeight: FontWeight.w700),
                        );
                      },
                    ),
                    //SizedBox(height: 10),
                    //SizedBox(height: 10),//puts empty box to space things out
                    buildTimer(),
                    //const SizedBox(height: 10),
                    buildButtons(),
                  ],
                ),
              ),
            ),
          );
    
      @override
      Widget buildButtons() {
        final isRunning = timer == null ? false : timer!.isActive;
        final isCompleted = seconds == maxSeconds || seconds == 0;
        return isRunning || !isCompleted
            ? Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  ButtonWidget(
                    text: isRunning ? "Pause" : "Resume",
                    onClicked: () {
                      if (isRunning) {
                        stopTimer(reset: false);
                      } else {
                        startTimer(reset: false);
                      }
                    },
                  ),
                  const SizedBox(width: 12),
                  ButtonWidget(text: "Cancel", onClicked: stopTimer)
                ],
              )
            : ButtonWidget(
                text: "Start Timer!",
                color: Colors.black,
                backgroundColor: Colors.white,
                onClicked: () {
                  startTimer();
                },
              );
      }
    
      Widget buildTimer() => SizedBox(
            width: 200,
            height: 200,
            child: Stack(
              fit: StackFit.expand,
              children: [
                CircularProgressIndicator(
                  value: seconds / maxSeconds,
                  //if you delete 1 - then it goes to other direction
                  valueColor: AlwaysStoppedAnimation(Colors.white),
                  strokeWidth: 12,
                  backgroundColor: Colors.greenAccent,
                ),
                Center(child: buildTime()),
              ],
            ),
          );
    
      Widget buildTime() {
        if (seconds == 0) {
          return Icon(Icons.done, color: Colors.greenAccent, size: 112);
        } else {
          return Text(
            "$seconds",
            style: TextStyle(
              fontWeight: FontWeight.bold,
              color: Colors.white,
              fontSize: 80,
            ),
          );
        }
      }
    }
Bn Minki
  • 155
  • 7

1 Answers1

0

You're doing three things wrong.

First: void rannn(String) is a function, if you simply try to print a function you'll get exactly what you're getting now.

Second: void rannn(String) is a void function, so it won't return a Future<String> for you to display. You should return a String from it, like:

Future<String> rann() async {
  return (_tasks.toList()..shuffle()).first.name;
}

Third: You should call the function with () to have access to it's return value:

"${Provider.of<TaskData>(context).rannn()} Tasks",

Problem is, this is a function that returns a Future, so it won't work either.

The solution is to use a FutureBuilder widget, so that you can pass Provider.of<TaskData>(context).rannn() to it's future parameter and wait for the returned future to finally display it in your Text widget

Example:

Future<String> rannn() async {
  await Future.delayed(const Duration(seconds: 2)); // Just so you can see the Future loading
  return (_tasks.toList()..shuffle()).first.name;
}


Widget build(BuildContext context) => Container(
  color: Colors.transparent,
  child: Scaffold(
    backgroundColor: Colors.blue,
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          FutureBuilder(
            future: Provider.of<TaskData>(context).rannn(),
            builder: (context, snapshot) {
              if (!snapshot.hasData) {
                return const Text('Loading...');
              }
              return Text('${snapshot.data}');
            },
          ),
        ],
      ),
    ),
  ),
);
pedro pimont
  • 2,764
  • 1
  • 11
  • 24
  • Thank you so much for the help. I went over the future builder documentation, but I can't seem to figure out where/how to use that widget, could you help me with this one? – Bn Minki Sep 15 '21 at 20:08
  • sure, ill show you, I'm editing the answer – pedro pimont Sep 15 '21 at 21:50
  • Ok thank you so much ! I have managed to figure something out like this after 2 hours, but it gives me "bad state" – Bn Minki Sep 15 '21 at 21:52
  • @override Widget build(BuildContext context) { return new FutureBuilder( future: Provider.of(context).rann(), builder: (BuildContext context, AsyncSnapshot text) { return new Container( child: new Text( text.requireData, //text.requireData, -- works but shows some bad state: snapshot has neither data nor error style: new TextStyle( fontWeight: FontWeight.bold, fontSize: 19.0, ), )); }); } – Bn Minki Sep 15 '21 at 21:53
  • added the example – pedro pimont Sep 15 '21 at 21:57
  • Thank you so much!! It works – Bn Minki Sep 16 '21 at 14:48
  • Hi there, I have one issue though. When I start the timer on that page, the text keeps updating every second, same when I press some button it keeps changing? - Not sure how to fix this, I tried looking it up on google for 2 hours now :| – Bn Minki Sep 17 '21 at 12:42
  • I have no way of knowing what your timer is doing because its not on the code of the question. But he is probably notifiying listeners triggering rebuilds every second. – pedro pimont Sep 17 '21 at 12:46
  • I have added all-timer code in my original post (Edited) – Bn Minki Sep 17 '21 at 12:49
  • it's just expected that CustomMainPageState is rebuilding itself since you're using setState inside of it. If you want to rebuild only portion of the screen you should extract it on its own widget and use setState only inside of it – pedro pimont Sep 17 '21 at 12:59
  • Sorry i forgot to add another class that I had above all that code, updated the code. - Does it change anything ? Or it still applies the same and i need to extract the widget of timer and use the set state inside there? – Bn Minki Sep 17 '21 at 13:11
  • Same thing, they are being called on the same build method – pedro pimont Sep 17 '21 at 13:14
  • Hmm, I tried playing around and looking up documentation but I think I won't be able to sort it out :| Could you help me please:? -- Quite tricky, because i want, when you click button on main page (It shows random text from the list on the new page with timer) and what it will look like the text should be stateless? but then the timer on that page is stateful, so no idea how to make it all work. – Bn Minki Sep 17 '21 at 14:15
  • Ok, i finally managed to get it to work after some time lol. I found this link (Below) and I somehow managed to create a different class and it all works, now just need some formatting to look how I want. Thank you so much for help bro ! https://stackoverflow.com/questions/52249578/how-to-deal-with-unwanted-widget-build – Bn Minki Sep 17 '21 at 14:33
  • Glad you did it! thanks for letting me know – pedro pimont Sep 17 '21 at 14:43