Как получить список из будущего и использовать его внутри listView - PullRequest
0 голосов
/ 26 апреля 2019

Я пытаюсь получить список всех файлов в определенном каталоге.

Я получаю файлы из будущей функции с именем getUserVideos(), если внутри функции я пытаюсь распечатать данные, я вижу результат, но не могу использовать данные вне функции.

class _mediaUtentiState extends State<mediaUtenti> {
  var lightBlue = Color.fromRGBO(0, 197, 205, 1.0);
  var _imagesDir;


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

  List<String> Names = [
    'Abhishek',
    'John',
    'Robert',
    'Shyam',
    'Sita',
    'Gita',
    'Nitish'
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: lightBlue,
      appBar: new AppBar(
        title: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Container(padding: const EdgeInsets.all(8.0), child: Text('Nome')),
            Container(
              child: CircleAvatar(
                backgroundImage: NetworkImage('http://i.pravatar.cc/300'),
              ),
            ),
          ],
        ),
        backgroundColor: purple,
      ),

      body: new Container(
        child: new ListView.builder(
          reverse: false,
          itemBuilder: (_, int index) => EachList(this.Names[index]),
          itemCount: this.Names.length,
        ),
      ),
    );
  }

  Future<String> getUsersVideos() async {
    print('something');
    final Directory extDir = await getExternalStorageDirectory();
    final String dirPath = '${extDir.path}/Movies/Veople';
    final myDir = new Directory(dirPath);
    List<FileSystemEntity> _images;
    _images = myDir.listSync(recursive: true, followLinks: false);
    print(_images.length);
    _imagesDir = _images;
  }
}

class EachList extends StatelessWidget {
  final String name;
  EachList(this.name);
  @override
  Widget build(BuildContext context) {
    return new Card(
      child: new Container(
        padding: EdgeInsets.all(8.0),
        child: new Row(
          children: <Widget>[
            new CircleAvatar(
              child: new Text(name[0]),
            ),
            new Padding(padding: EdgeInsets.only(right: 10.0)),
            new Text(
              name,
              style: TextStyle(fontSize: 20.0),
            )
          ],
        ),
      ),
    );
  }
}

сейчас я просто показываю список имен, но хочу показать карточку для каждого файла в пути.

например, в функции getUserVideos() когда я пытаюсь напечатать imagesDir я получаю правильный результат [File: '/storage/emulated/0/Movies/Veople/1556217605345.mp4', File: '/storage/emulated/0/Movies/Veople/1556217605345.png', File: '/storage/emulated/0/Movies/Veople/1556217632709.mp4', File: ...] Но я никак не могу получить доступ к _imageDir из этой функции.

Я уверен, что можно решить эту проблему за несколько строк, но сейчас это 3 часа, и я не могу найти решение.

Thankyou!

1 Ответ

1 голос
/ 26 апреля 2019

Я думал, что наверняка на этот вопрос уже ответили, но, хотя есть много вопросов о FutureBuilder и списках, ни один не совсем такой или не получил адекватного ответа.

Вот как я это сделаю:

import 'dart:io';

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

Future<List<FileSystemEntity>> _getUsersVideos() async {
  print('something');
  final Directory extDir = await getExternalStorageDirectory();
  final String dirPath = '${extDir.path}/Movies/Veople';
  final myDir = new Directory(dirPath);
  List<FileSystemEntity> _images = myDir.listSync(recursive: true, followLinks: false);
  return _images;
}

class ListFromFuture extends StatefulWidget {
  @override
  _ListFromFutureState createState() => _ListFromFutureState();
}

class _ListFromFutureState extends State<ListFromFuture> {
  Future<List<FileSystemEntity>> future;

  @override
  void initState() {
    super.initState();
    future = _getUsersVideos();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: future,
      builder: (context, snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
          case ConnectionState.active:
            return Container(
              alignment: Alignment.center,
              child: Text("Loading"),
            );
            break;
          case ConnectionState.done:
            if (snapshot.hasError) {
              // return whatever you'd do for this case, probably an error
              return Container(
                alignment: Alignment.center,
                child: Text("Error: ${snapshot.error}"),
              );
            }
            var data = snapshot.data;
            return new ListView.builder(
              reverse: false,
              itemBuilder: (_, int index) => EachList(data[index]),
              itemCount: data.length,
            );
            break;
        }
      },
    );
  }
}

Важными частями этого являются:

  1. в будущем устанавливается только initState, а не функция сборки. Это гарантирует, что он не вызывается каждый раз, когда виджет строит
  2. Я занимаюсь всеми случаями, когда либо есть ошибка, либо будущее еще не завершено.

Если честно, ваш пример на самом деле очень близок к тому, чтобы заставить его работать. Все, что вам нужно сделать, это обернуть строку, где вы установили _imagesDir = images в setState(() => ...), и она должна работать (при условии, что список не вернется пустым). Вы также должны проверять наличие _imagesDir == null, иначе вы можете получить исключения нулевого указателя.

...