Flutter, StreamController не работает при извлечении изображения из сети - PullRequest
0 голосов
/ 02 января 2019

Я практикую Stream и реализовал простое приложение, которое выбирает изображение и показывает на экране.

Вот мой код, но он ничего не показывает, почему ??

Я изучаю StreamController и его использование, поэтому я не хочу использовать Future или другой виджет. Эта логика работала на простом счетчике приложения.

class MyAppPageState extends State<MyAppPage> {

  StreamController<List<String>> _controller = StreamController<List<String>>();

  @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(backgroundColor: Colors.orange),
        body: Center(
          child: StreamBuilder(
              stream: _controller.stream,
              builder: (BuildContext context, AsyncSnapshot snapshot) => 
                Image.network(snapshot.data[0])
          )
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => _addDataToStream()
        ),
      );
    }

    void _addDataToStream() {
      http.get('https://comic.naver.com/webtoon/weekdayList.nhn?week=mon')
        .then((response){
          dom.Document document = parser.parse(response.body);
          final e = document.querySelectorAll('.img_list .thumb');
          List<String> url = e.map((element){
            return element.getElementsByTagName('img')[0]
              .attributes['src'];
          }).toList();
          _controller.sink.add(url);
      });
    }

    @override
      void dispose() {
        _controller.close();
        super.dispose();
      }
}

1 Ответ

0 голосов
/ 02 января 2019

Ваш код работает нормально, за исключением небольшой ошибки.

Когда мы открыли приложение в первый раз, оно будет отображать NoSuchMethodError, например:

enter image description here

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

initialData: <List<String>>[],

Нам также нужно написать несколько if операторов.

if (!snapshot.hasData) return Text('No Data');

if (snapshot.data.length == 0) return Text('No Data');

return Image.network(snapshot.data[0]);

Я изменил ваш код и создал класс BLoC для использования.

Это BLOC:

//somebloc.dart
import "dart:async";

class SomeBloc {

    final _data = StreamController<List<String>>();
    Stream<List<String>> get data => _data.stream;

    final _url = StreamController<List<String>>();
    Sink<List<String>> get urlIn => _url.sink;
    Stream<List<String>> get urlOut => _url.stream;


    SomeBloc() {
        urlOut.listen(_handleData);
    }

    void _handleData(List<String> urlList) {       
        _data.add(urlList);         
    }

}

Модифицированная основная:

//main.dart
import "dart:async";

import 'package:http/http.dart' as http;
import 'package:html/parser.dart' as parser;
import 'package:html/dom.dart' as dom;

import "somebloc.dart"; // the bloc


...

class MyAppPageState extends State<MyAppPage> {

    @override
    Widget build(BuildContext context) {
        SomeBloc bloc = SomeBloc();

        return Scaffold(
            appBar: AppBar(backgroundColor: Colors.orange),
            body: Center(
                child: StreamBuilder(
                    stream: bloc.data, 
                    initialData: <List<String>>[],
                    builder: (BuildContext context, AsyncSnapshot snapshot){

                        if (!snapshot.hasData) return Text('No Data');

                        if (snapshot.data.length == 0) return Text('No Data');

                        return Image.network(snapshot.data[0]);



                    }
                    )
                ),
           floatingActionButton: FloatingActionButton(
               onPressed: () => _addDataToStream()
               ),
           );
     }

    void _addDataToStream() {

        http.get('https://comic.naver.com/webtoon/weekdayList.nhn?week=mon')
            .then((response){
                dom.Document document = parser.parse(response.body);
                final e = document.querySelectorAll('.img_list .thumb');
                List<String> url = e.map((element){
                    return element.getElementsByTagName('img')[0]
                       .attributes['src'];
                       }).toList();
                bloc.urlIn.add(url);
            });
    }

}

...

Если вы заинтересованы в использовании потоков, я бы порекомендовал вам использовать пакет rxdart .

//somebloc.dart using rxdart
import "package:rxdart/rxdart.dart";
import "dart:async";

class SomeBloc {

    final _data = BehaviorSubject<List<String>>(); // from rxdart
    Stream<List<String>> get data => _data.stream;

    final _url = StreamController<List<String>>();
    Sink<List<String>> get urlIn => _url.sink;
    Stream<List<String>> get urlOut => _url.stream;


    SomeBloc() {
        urlOut.listen(_handleData);
    }

    void _handleData(List<String> urlList) {       
        _data.add(urlList);         
    }

}

Вот результат:

enter image description here

...