#flutter
#flutter
Вопрос:
Я создал этот код, и я хочу, чтобы при нажатии на кнопку происходило то, что я хочу, чтобы диаграмма элементов повторно отображалась с новыми значениями (которые должны быть старыми значениями, но ценность еды увеличилась на 1). Я использую диаграмму элементов из пакета pie_chart: 0.8.0. Deposit — это не что иное, как pojo (категория строки и вклад int).bloc.dart содержит глобальный экземпляр блока, средство получения потока и инициализацию потока типа Вот мой код:
import 'package:flutter/material.dart';
import 'package:pie_chart/pie_chart.dart';
import 'bloc.dart';
import 'Deposit.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'bloc Chart',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
Map<String, double> datamap = new Map();
@override
Widget build(BuildContext context) {
datamap.putIfAbsent("Food", () => 5);
datamap.putIfAbsent("transportation", () => 3);
return Scaffold(
appBar: AppBar(
title: Text("PieChart using blocs"),
),
body: Column(
children: <Widget>[
StreamBuilder<Deposit>(
stream: bloc.data, //A stream of Deposit data
builder: (context, snapshot) {
addDeposit(Deposit("Food", 1), datamap);
debugPrint("Value of food in map is: ${datamap["Food"]}");
return PieChart(dataMap: datamap);
}),
SizedBox.fromSize(
size: Size(20, 10),
),
RaisedButton(
onPressed: () {
bloc.add(Deposit("Food", 1)); //returns the stream.add
},
child: Icon(Icons.add),
),
],
),
);
}
void addDeposit(Deposit dep, Map<String, double> map) {
if (map.containsKey(dep.category)) {
map.update(dep.category, (value) => value dep.price);
} else
map.putIfAbsent(dep.category, () => dep.price);
}
}
Комментарии:
1. попробуйте это, сначала закройте поток, затем добавьте новые данные
2. Где именно я должен закрыть свой поток? А также почему я должен хотеть, чтобы он был закрыт во время его использования?
3. bloc.sink.close(); bloc.sink.add(Депозит(«Еда», 1));
4. @BenjithKizhisseri если вы закроете свой приемник, как вы сможете что-либо добавить в этот приемник? в
close()
документах метода говорится: «Сообщает приемнику потока, что дополнительные потоки не будут добавлены».5. @pskink это bloc.close(); это bloc.sink.close(); оба они разные
Ответ №1:
Я думаю, ваша проблема в том, что поток не запускает новые события. Вам не нужно закрывать поток для восстановления. Я не вижу нигде в вашем коде, где вы запускаете новые события для потока. Проверьте приведенный ниже код, чтобы увидеть простой способ, как вы можете обновить a StatelessWidget
с помощью StreamBuilder
.
class CustomWidgetWithStream extends StatelessWidget {
final CustomBlock block = CustomBlock();
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
StreamBuilder(
stream: block.stream,
builder: (context, stream) {
return Text("${stream.data.toString()}");
}),
RaisedButton(
onPressed: () {
block.incrementNumber();
},
child: Text("Increment"),
)
],
);
}
}
class CustomBlock {
num counter = 10;
final StreamController<num> _controller = StreamController();
Stream<num> get stream => _controller.stream;
CustomBlock() {
_controller.onListen = () {
_controller.add(counter); // triggered when the first subscriber is added
};
}
void incrementNumber() {
counter = 1;
_controller.add(counter); // ADD NEW EVENT TO THE STREAM
}
dispose() {
_controller.close();
}
}
Хотя это рабочий фрагмент кода, я бы настоятельно рекомендовал изменить ваш виджет с StatelessWidget
на StatefulWidget
по двум причинам:
* если вы идете «по инструкции», если виджет изменяет содержимое сам по себе, то это не StatelessWidget
, виджет без состояния отображает только данные, которые ему предоставлены. В вашем случае виджет обрабатывает нажатие, а затем решает, что делать дальше и как обновить себя.
* если вы используете потоки, в виджете с отслеживанием состояния вы можете безопасно закрыть поток, как вы можете видеть в приведенном выше коде, безопасного способа закрыть поток не существует. Если вы не закроете поток, может возникнуть нежелательное поведение или даже сбой.
Комментарии:
1. Хорошо, признайтесь мне, я новичок в flutter. Этот код — всего лишь тест, поскольку моя настоящая цель — иметь кнопку «добавить депозит», которая позволила бы пользователю вводить категорию и цену, что затем привело бы к обновлению диаграммы. Я прошел курс по udemy, в котором упоминалось, что шаблон bloc рекомендуется flutter. Диаграмма элементов будет телом моего эшафота на моей домашней странице, и я пытаюсь избежать того, чтобы домашняя страница была виджетом с отслеживанием состояния. Я в замешательстве, почему диаграмма элементов не выполняется повторный рендеринг, хотя должна (в потоке Streambuilder данные добавляются к нему с помощью bloc.add в кнопке
2. Я не совсем понимаю, как мне заставить мою кнопку взаимодействовать с виджетом, идея в моей голове была простой. Кнопка добавить событие в поток, streambuilder обновляет круговую диаграмму, и я избегаю отображения состояния всей моей домашней страницы. После того, как это сработает, я бы попытался сделать так, чтобы автоматически, когда я «добавляю данные» в поток, карта, используемая диаграммой элементов, также обновлялась, прямо сейчас я вручную обновляю ее с помощью addDeposit (). Также обратите внимание, что я пытался заменить диаграмму элементов просто текстом, отображающим карту данных [Food], и она обновлялась каждый раз, когда я нажимал кнопку.
3. Можете ли вы опубликовать код из «блока` и где вы его инициализируете? Я не могу найти код для этого.
4. Можете ли вы изменить
_data.sink.add
на_data.add
?
Ответ №2:
Это мой файл блока
import 'package:rxdart/rxdart.dart';
import 'package:testing/Deposit.dart';
class Bloc{
final _data = new BehaviorSubject<Deposit>();
Stream<Deposit> get data => _data.stream;
Function(Deposit) get add => _data.sink.add;
void dispose(){
_data.close();
}
}
Bloc bloc = new Bloc();