我可以使用Future< String>来“填充"Text()小部件而不是使用Flutter中的FutureBuilder吗?

q8l4jmvw  于 2022-11-25  发布在  Flutter
关注(0)|答案(2)|浏览(160)

我正在尝试更好地理解Futures in Flutter。在本例中,我的应用调用了一个API来获取Future<String>类型的一些信息。我想在Text()小部件中显示这些信息。但是,由于我的String被 Package 在Future中,我无法将这些信息放入Text()小部件中。我不知道如何在不借助FutureBuilder创建小部件树的情况下处理这个问题。
下面的例子使用了一个FutureBuilder,它运行得很好。注意,我已经注解掉了下面靠近底部的一行:
Future<String> category = getData();
是否可以将category转换为String,然后将其放到我的Text()小部件中?

import 'package:flutter/material.dart';
import 'cocktails.dart';

class CocktailScreen extends StatefulWidget {
  const CocktailScreen({super.key});

  @override
  State<CocktailScreen> createState() => _CocktailScreenState();
}

class _CocktailScreenState extends State<CocktailScreen> {
  @override
  Widget build(BuildContext context) {
    Cocktails cocktails = Cocktails();

    Future<String> getData() async {
      var data = await cocktails.getCocktailByName('margarita');
      String category = data['drinks'][0]['strCategory'];
      print('Category: ${data["drinks"][0]["strCategory"]}');
      return category;
    }

    FutureBuilder categoryText = FutureBuilder(
      initialData: '',
      future: getData(),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasData) {
            return Text(snapshot.data);
          } else if (snapshot.hasError) {
            return Text(snapshot.error.toString());
          }
        }
        return const CircularProgressIndicator();
      },
    );

    //Future<String> category = getData();

    return Center(
      child: categoryText,
    );
  }
}

下面是我的Cocktails类:

import 'networking.dart';

const apiKey = '1';
const apiUrl = 'https://www.thecocktaildb.com/api/json/v1/1/search.php';

class Cocktails {
  Future<dynamic> getCocktailByName(String cocktailName) async {
    NetworkHelper networkHelper =
        NetworkHelper('$apiUrl?s=$cocktailName&apikey=$apiKey');
    dynamic cocktailData = await networkHelper.getData();
    return cocktailData;
  }
}

下面是我的NetworkHelper类:

import 'package:http/http.dart' as http;
import 'dart:convert';

class NetworkHelper {
  NetworkHelper(this.url);

  final String url;

  Future<dynamic> getData() async {
    http.Response response = await http.get(Uri.parse(url));
    if (response.statusCode == 200) {
      String data = response.body;
      var decodedData = jsonDecode(data);
      return decodedData;
    } else {
      //print('Error: ${response.statusCode}');
      throw 'Sorry, there\'s a problem with the request';
    }
  }
}
3duebb1j

3duebb1j1#

是的,您可以在不使用Using FutureBuilder的情况下,通过在initState()中调用Future,并使用then关键字来实现获取Future的值并根据更新状态,以便在Future返回快照时更新状态。

class StatefuleWidget extends StatefulWidget {
  const StatefuleWidget({super.key});

  @override
  State<StatefuleWidget> createState() => _StatefuleWidgetState();
}

class _StatefuleWidgetState extends State<StatefuleWidget> {
  String? text;

  Future<String> getData() async {
    var data = await cocktails.getCocktailByName('margarita');
    String category = data['drinks'][0]['strCategory'];
    print('Category: ${data["drinks"][0]["strCategory"]}');
    return category;
  }

  @override
  void initState() {
    super.initState();
    getData().then((value) {
      setState(() {
        text = value;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Text(text ?? 'Loading');
  }
}

在这里,我将text变量设置为可空,然后在Text()小部件的实现中,我将其设置为一个loading文本作为默认值,直到Future完成为止。

ccrfmcuu

ccrfmcuu2#

最好的方法是使用FutureBuilder

FutureBuilder categoryText = FutureBuilder<String>(
        future: getData(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              return Text('Loading....');
            default:
              if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              } else {
                var data = snapshot.data ?? '';

                return Text(data);
              }
          }
        },
      ),

但如果您不想使用FutureBuilder,请首先定义一个字符串变量,如下所示,然后将adasd更改为:

String category = '';

Future<void> getData() async {
  var data = await cocktails.getCocktailByName('margarita');
  setState(() {
     category = data['drinks'][0]['strCategory'];
  });
}

然后在initState中调用它:

@override
  void initState() {
    super.initState();
    getData();
  }

并像这样使用它:

@override
  Widget build(BuildContext context) {
    return Center(
      child: Text(category),
    );
  }

记住在构建方法之外而不是在构建方法内部定义categorygetDatacocktails

相关问题