Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to transform Future<List<Map> to List<Map> in Dart language?

Tags:

flutter

dart

I have a question in coding with dart language. How to transform a Future to the normal List? In my program, I need the result from web to continue next step and I don't know how to do it. In my case, I need to return the value of variable "data" as a List.

class _MyAppState extends State<MyApp> {
    static List getList() {
    var url = "http://watcherman.cn/web/json.php";
    var data;
    HttpClient client = new HttpClient();
    client.getUrl(Uri.parse(url))
      .then((HttpClientRequest request) => request.close())
    .then((HttpClientResponse response) {
      response.transform(UTF8.decoder).listen((contents) {
        String jsonContent = contents.toString();
        data = JSON.decode(jsonContent);
      });
    });
    return data;
  }
}

But it seems like not execute the network part. The flutter code part seems can't accept a Future.

class _MyAppState extends State<MyApp> {
  static List content = getList();
  @override
  Widget build(BuildContext context) {
    return new Container(
        child: new ListView.builder(
            scrollDirection: Axis.vertical,
            padding: new EdgeInsets.all(6.0),
            itemCount: content.length,
            itemBuilder: (BuildContext context, int index) {
              return new Container(
                  alignment: FractionalOffset.center,
                  margin: new EdgeInsets.only(bottom: 6.0),
                  padding: new EdgeInsets.all(6.0),
                  color: Colors.blueGrey,
                  child: new Text(content[index]["title"])
              );
            }
        )
    );
  }
}
like image 938
watcher man Avatar asked Jun 01 '17 03:06

watcher man


2 Answers

You should rewrite your getList method to return a Future<List>. It's possible to do this with a chain of then() invocations, but far more readable IMO to use async/await.

Once you have a method that returns a Future<List>, you can use FutureBuilder to build a tree that depend on the results of the asynchronous computation.

screenshot

import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:convert';
import 'dart:async';

void main() {
  runApp(new MaterialApp(
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  State createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {

  static Future<List> getList() async {
    var url = "http://watcherman.cn/web/json.php";
    HttpClient client = new HttpClient();
    HttpClientRequest request = await client.getUrl(Uri.parse(url));
    HttpClientResponse response = await request.close();
    return response.transform(UTF8.decoder).transform(JSON.decoder).toList();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Futures Demo'),
      ),
      body: new FutureBuilder(
        future: getList(),
        builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
          if (!snapshot.hasData)
            return new Container();
          List content = snapshot.data[0];
          return new ListView.builder(
            scrollDirection: Axis.vertical,
            padding: new EdgeInsets.all(6.0),
            itemCount: content.length,
            itemBuilder: (BuildContext context, int index) {
              return new Container(
                alignment: FractionalOffset.center,
                margin: new EdgeInsets.only(bottom: 6.0),
                padding: new EdgeInsets.all(6.0),
                color: Colors.blueGrey,
                child: new Text('${content[index]['title']}'),
              );
            },
          );
        }
      )
    );
  }
}
like image 181
Collin Jackson Avatar answered Oct 10 '22 10:10

Collin Jackson


You cannot escape from being asynchronous.

In Dart, a function either returns a value or a Future. It returns a future when the result isn't ready yet when the function returns, it will only be available at a later time.

That means that you are stuck if all you have is a Future and you want the value right now, because the value just isn't there yet. You cannot return the List now, because the Future<List> doesn't have a list now, it only has it later.

So, you have to wait for that future, var data = await client.getUrl(...)..., and that means that your function must be asynchronous too. So, make the getList function return a Future<List> instead of a List, because that's all it can do.

The alternative, which Dart doesn't support, would be a blocking operation that stops execution until a value is available, and then continues the normal execution. That's a problem in a single-threaded language (like Dart and JavaScript, which Dart must compile to) because blocking means nothing happens and the UI becoming unresponsive.

So, if your result depends on the value of a future, then your function must be asynchronous too and return its own result as a future.

like image 39
lrn Avatar answered Oct 10 '22 11:10

lrn