web-dev-qa-db-ja.com

Flutter:Futureから価値を引き出すための正しいアプローチ

画像のディレクトリパスを返す関数があります。ディレクトリが存在するかどうかなどの追加のチェックを実行し、それに応じて動作します。

これが私のコードです:

_Future<String> getImagesPath() async {
   final Directory appDir = await getApplicationDocumentsDirectory();
   final String appDirPath = appDir.path;

   final String imgPath = appDirPath + '/data/images';

   final imgDir = new Directory(imgPath);

   bool dirExists = await imgDir.exists();

   if (!dirExists) {
        await new Directory(imgPath).create(recursive: true);
   }

   return imgPath;

}
_

このコードは期待どおりに機能しますが、Futureから値を取得する際に問題が発生します。

ケースシナリオ:ローカルデータベースにデータが保存されており、それをリストビュー内で表示しようとしています。この answer で説明されているように、私はFutureBuilderを使用しています。各データ行には、イメージが関連付けられています(関連付けられているという意味で、イメージ名はdbに格納されています)。

_Widget build_メソッド内に、次のコードがあります。

_@override
Widget build(BuildContext context) {
 getImagesPath().then((path){
     imagesPath = path;
     print(imagesPath); //prints correct path
   });
 print(imagesPath);   //prints null

return Scaffold(
    //removed
    body: FutureBuilder<List>(
        future: databaseHelper.getList(),
        initialData: List(),
        builder: (context, snapshot) {
          return snapshot.hasData
              ? ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (_, int position) {
                    final item = snapshot.data[position];
                    final image = "$imagesPath/${item.row[0]}.jpg";
                    return Card(
                        child: ListTile(
                      leading: Image.asset(image),
                      title: Text(item.row[1]),
                      subtitle: Text(item.row[2]),
                      trailing: Icon(Icons.launch),
                    ));
                  })
              : Center(
                  child: CircularProgressIndicator(),
                );
        }));
_

}

_.then_内でのreturn Scaffold(.....)のシフトは機能しません。ウィジェットのビルドは何も返さないからです。

私が見つけた他のオプションは_async/await_ですが、最後に、同じ問題、以下のコードが利用可能です:

__getImagesPath() async {
    return await imgPath();
}
_

_getImagesPath()を呼び出すと、実際のデータではなくFutureが返されます。

私は非常に小さな論理的な間違いがあると思いますが、それを自分で見つけることはできません。

2
Alena

このコードをFutureBuilder内に移動すると、問題が解決します。

getImagesPath().then((path){
 imagesPath = path;
 print(imagesPath); //prints correct path
});

したがって、最終的なコードは次のようになります。

@override
Widget build(BuildContext context) {

return Scaffold(
    //removed
    body: FutureBuilder<List>(
        future: databaseHelper.getList(),
        initialData: List(),
        builder: (context, snapshot) {
          return snapshot.hasData
              ? ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (_, int position) {
                    getImagesPath().then((path){
                        imagesPath = path;
                    });

                    final item = snapshot.data[position];
                    final image = "$imagesPath/${item.row[0]}.jpg";
                    return Card(
                        child: ListTile(
                      leading: Image.file(File(image)),
                      title: Text(item.row[1]),
                      subtitle: Text(item.row[2]),
                      trailing: Icon(Icons.launch),
                    ));
                  })
              : Center(
                  child: CircularProgressIndicator(),
                );
        }));
}

それが役に立てば幸い!

2
Atlas_Gondal