skip to Main Content

Why do I keep getting ‘Instance of…’ when I’m trying to get a String. What’s wrong with the function?

Future<string?> counter() async {
    Future.delayed(const Duration(seconds: 5), () {
      context.watch<FoodCount>().display(widget.food).toString();
      return widget.food.quantity.toString();
    });
    int count = widget.food.quantity;
    // print(count);
    return count;
  }

This is what I’m trying to do:

class FoodQuantity extends StatefulWidget {
  final Food food;
  FoodQuantity(this.food);

  @override
  State<FoodQuantity> createState() => _FoodQuantityState();
}

class _FoodQuantityState extends State<FoodQuantity> {
  final int amount = 0;

  String getCurrency() {
    var format = NumberFormat.simpleCurrency(name: 'NGN');
    return format.currencySymbol;
  }

  Future<int> counter() async {
    final int result = await Future.delayed(const Duration(seconds: 5), () {
      int result = context.read<FoodCount>().display(widget.food);
      return result;
    });
    return result;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.maxFinite,
      height: 40,
      child: Stack(
        children: [
          Align(
            alignment: const Alignment(-1, 0), //0.3
            child: Container(
              width: 120,
              height: double.maxFinite,
              decoration: BoxDecoration(
                color: Colors.grey.withOpacity(0.1),
                borderRadius: BorderRadius.circular(30),
              ),
              child: Row(
                children: [
                  const SizedBox(width: 15), //Spacing
                  Text(
                    getCurrency(),
                    style: const TextStyle(
                        fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                  Text(
                    widget.food.price.toString(),
                    style: const TextStyle(
                      fontSize: 24,
                      fontWeight: FontWeight.bold,
                    ),
                  )
                ],
              ),
            ),
          ),
          Align(
            alignment: const Alignment(1, 0), //0.3
            child: Container(
              height: double.maxFinite,
              width: 120,
              decoration: BoxDecoration(
                color: Color(0xff453658),
                borderRadius: BorderRadius.circular(30),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  GestureDetector(
                    onTap: () {
                      if (context.read<Counter>().count != 0) {
                        context.read<Counter>().decrement();
                        // widget.food.quantity--;
                        userOrders.remove(widget.food);
                        context.read<FoodCount>().decrement(widget.food);
                        setState(() {});
                      } else {
                        context.read()<Counter>();
                      }
                    },
                    child: const Text(
                      '-',
                      style: TextStyle(
                        fontSize: 30,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  Container(
                    padding: const EdgeInsets.all(12),
                    decoration: const BoxDecoration(
                      shape: BoxShape.circle,
                      color: Colors.white,
                    ),
                    child: Text(
                      counter().toString(),
                      // context
                      //     .watch<FoodCount>()
                      //     .display(widget.food)
                      //     .toString(),
                      // widget.food.quantity.toString(),
                      style: const TextStyle(
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  GestureDetector(
                    onTap: () {
                      context.read<Counter>().increment();
                      context.read<FoodCount>().increment(widget.food);
                      // widget.food.quantity++;
                      userOrders.add(widget.food);
                      setState(() {});
                    },
                    child: const Text(
                      '+',
                      style: TextStyle(
                        fontSize: 30,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

I made a provider class FoodCount that monitors the value quantity of object type Food. The async function is supposed to simply return the quantity of the Food provided to it

Provider:

class FoodCount with ChangeNotifier {

  int increment(Food food) {
    food.quantity++;
    int foodCount = food.quantity;
    notifyListeners();
    return foodCount;
  }

  int decrement(Food food) {
    food.quantity--;
    int foodCount = food.quantity;
    notifyListeners();
    return foodCount;
  }

  int display(Food food) {
    int count = food.quantity;
    notifyListeners();
    return count;
  }

  void update() {
    notifyListeners();
  }
}

Food:

class Food {
  String imgUrl;
  String desc;
  String name;
  String waitTime;
  num score;
  int price;
  int quantity;
  bool favourited;
  List<Map<String, String>> ingredients;
  String about;
  bool highlight;
  Food(this.imgUrl, this.desc, this.name, this.waitTime, this.score, this.price,
      this.quantity, this.ingredients, this.about, this.favourited,
      {this.highlight = false});
}

3

Answers


  1. Future.delayed is by itself a Future, so you cannot track it without an await to keep the result.
    Take a look here, how you can make it, then take care of the difference about a sequential method and a Future method;

    Future<String?> counter() async {
        // Future.delayed is by itself a future, so you connot track it without an await to get the result
        final String result = await Future.delayed(const Duration(seconds: 5), () {
           var a = "I'm a Future after 5 seconds" ;
           return a;
        });
        
        return result; 
        // Here is not the result you want because this method might be not a Future I think
        // int count = widget.food.quantity;
        // print(count);
        // return count;
      }
    

    Or

      Future<String?> counter2() async {
        return  await Future.delayed(const Duration(seconds: 5), () {
          var a = "I'm a Future after 5 seconds" ;
          return a;
        });
    
        
        // Here is not the result you want because this method might be not a Future I think
        // int count = widget.food.quantity;
        // print(count);
        // return count;
      }
    
    Login or Signup to reply.
  2. When you work with Future and you want to get value from it, you should use await or then()
    try to use this code:

    await Future.delayed(const Duration(seconds: 5), () {
          context.watch<FoodCount>().display(widget.food).toString();
          return widget.food.quantity.toString();
        });
    
    Login or Signup to reply.
  3. First off, here’s a tip: you’re using Future.delayed as a way to get a value after a delay. Try splitting that up into two parts. Instead of

    Future.delayed(const Duration(seconds: 5), () {
      context.watch<FoodCount>().display(widget.food).toString();
      return widget.food.quantity.toString();
    });
    int count = widget.food.quantity;
    

    Try

    await Future.delayed(const Duration(seconds: 5));
    context.watch<FoodCount>().display(widget.food.toString());
    return widget.food.quantity.toString();
    

    Secondly, the other users are right: when you receive a Future<String>, you can’t actually get to the String without awaiting it. Problem is, you can use await in an async function, and build is not async. Conceptually, think of it as "you need to wait 5 seconds for the delay, but your user needs a UI now".

    You can solve this using FutureBuilder, which allows you to return some widget until the future finishes.

    // In your State class:
    late final Future<int> futureCounter;  // the future containing your data
    
    @override
    void initState() {
      // Start your counter now, before the UI loads
      futureCounter = counter();
      super.initState();
    }
    
    // in your build:
    Container(
      padding: const EdgeInsets.all(12),
      decoration: const BoxDecoration(
        shape: BoxShape.circle,
        color: Colors.white,
      ),
      child: FutureBuilder(
        future: futureCounter,
        builder: (context, snapshot) => Text(
          snapshot.hasData ? snapshot.data : "Loading...",
        )
        style: const TextStyle(fontWeight: FontWeight.bold),
      ),
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search