42

I want to get Future return value and use it like variable. I have this Future function

  Future<User> _fetchUserInfo(String id) async {
    User fetchedUser;
    await Firestore.instance
        .collection('user')
        .document(id)
        .get()
        .then((snapshot) {
      final User user = User(snapshot);
      fetchedUser = user;
    });
    return fetchedUser;
  }

And I want get value like so

final user = _fetchUserInfo(id);

However when I tried to use like this

new Text(user.userName);

Dart doesn't recognize as User class. It says dynamic.
How Can I get return value and use it?
Am I doing wrong way first of all? Any help is appreciated!

Daibaku
  • 11,416
  • 22
  • 71
  • 108

5 Answers5

64

You can simplify the code:

Future<User> _fetchUserInfo(String id) async {
    User fetchedUser;
    var snapshot = await Firestore.instance
        .collection('user')
        .document(id)
        .get();
    return User(snapshot);
  }

you also need async/await to get the value

void foo() async {
  final user = await _fetchUserInfo(id);
}
MendelG
  • 14,885
  • 4
  • 25
  • 52
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    thank you. so I need to create function in-place just to receive future's return value? this works but weird! – Jehad Nasser Jun 25 '19 at 13:41
  • 1
    I'm not sure what you mean exactly. I added the function to demonstrate where to place `async`. Your code most likely is already inside a function anyway. You can also always use `.then(...)` with a `Future`. You should also be aware that a `Future` is a unified handler for all kinds of callbacks, so "just to receive future's return value" sounds like you are not fully considering what's actually going on. – Günter Zöchbauer Jun 25 '19 at 13:47
  • 1
    you are right, I am new to Flutter, what I'm trying to understand is why this alone is not possible: `final user = await _fetchUserInfo(id);` so why to create a foo(); ? – Jehad Nasser Jun 25 '19 at 13:54
  • 2
    As mentioned `Future` is about callbacks where your code (the function you pass to `aFuture.then(...)`) is called when the result of the async execution becomes available eventually. If you use `async` this is a sign for Dart that this code makes use of the simplified async syntax that uses for example `await` at that it needs to rewrite this code to the `.then(...)` syntax before the code can actually be compiled. You don't want this automatically because `async` *always* requires the return type of such functions to be a `Future<...>` which one would try to avoid if possible. – Günter Zöchbauer Jun 25 '19 at 14:08
  • To fully understand `async`/`await` it might be a good idea to create an example that utilizes an async callback, first without using any special Dart syntax support (without using `Future` at all), then rewrite it to use `Future.then(...)`, and then rewrite it to use `async`/`await`. – Günter Zöchbauer Jun 25 '19 at 14:11
  • thank you so much, will check that, and according to what you just said, that I need to add the stream builder inside a `futer.then(...)` or inside a `async/await` in order to use the `user id` in the `where clause` in this code `StreamBuilder( stream: db.collection(...).where( "userId", isEqualTo: getTheUserFutureOrSomething )` – Jehad Nasser Jun 25 '19 at 14:23
  • mr. Günter, can you please have a look on this? https://stackoverflow.com/questions/56759571/how-to-build-a-stream-based-on-a-future-result-in-flutter thanks – Jehad Nasser Jun 25 '19 at 17:54
  • 1
    helped me with my solution. – Winter MC Mar 17 '21 at 21:38
12

use like this

var username;
dbHelper.getUsers().then((user) {
  username = user.getName;
});

this function returns future value

dbHelper.getUsers()

it is written like this

getUsers() async { .... }
Rashid Iqbal
  • 1,123
  • 13
  • 13
4

To add a little more detail on the original question from Daibaku which might help clarify using Futures in Flutter/dart, user was:

final user = _fetchUserInfo(id);

Without letting compiler infer type, that would be:

final Future<User> user = _fetchUserInfo(id);

Get & Use a Future Value

Daibaku asked how to get the return value of user & use it.

To use user in a Widget, your widget must watch/observe for changes, and rebuild itself when it does.

You can do this manually with a lot of boilerplate code, or you could use FutureBuilder, which has done this for you:

  FutureBuilder(future: user, builder: (context, snapshot) 
  {
    if (snapshot.hasData) return Text(snapshot.data.userName);
    return Container(width: 0.0, height: 0.0,);
  }

More explicitly, you could write the above as:

  FutureBuilder<User>(future: user, builder: (context, AsyncSnapshot<User> userSnapshot)
  {
    if (userSnapshot.hasData) return Text(userSnapshot.data.userName);
    return Container(width: 0.0, height: 0.0,);
  }

FutureBuilder in the above example, synchronously (i.e. immediately) returns a zero width/height Container Widget, but also attaches an observer to your future user, to know when Future data arrives.

When user is eventually updated with "data", FutureBuilder's observer is notified and it calls setState(), which starts a rebuild of itself. Now that snapshot.hasData is true, Text(snapshot.data.userName) is returned instead of the empty Container.


If you weren't using user within the synchronous world of Widget Element tree building and just wanted to print out the value for debugging you could attach an observer using then:

user.then((u) => print(u.userName));
Baker
  • 24,730
  • 11
  • 100
  • 106
1

There are two ways of getting a value from a Future.

  1. Using async-await:

    int _value = 0; // Instance variable.
    
    void func() async {
      int value = await _yourFuture(); // Await on your future.
      setState(() {
        _value = value;
      });
    }
    
  2. Using then:

    int _value = 0; // Instance variable.
    
    void func() {
      _getPref().then((value) {
        setState(() {
          _value = value; // Future is completed with a value.
        });
      });
    }
    
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
-20
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

class ThreadExample implements Callable<String>{

    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        return "Ashish";
    }

}
public class FutureThreadExample {

    public static void main(String a[]) throws InterruptedException, ExecutionException {
        ExecutorService executorService=Executors.newFixedThreadPool(1);
        List <Future<String>>objList=new ArrayList<Future<String>>();
       for(int i=0;i<10;i++) {
            Future<String> obj=executorService.submit(new ThreadExample());
            objList.add(obj);
       }
        for( Future<String> fut:objList) {
            System.out.println(fut.get());
        }
        executorService.shutdown();
    }


}
Ashish Yadav
  • 7
  • 1
  • 1
  • 6