How to update UI in Flutter - flutter

I'm reading a list from my local Json file and i'm trying to sort the list by either number or alphabet and update the UI depend on user choice.
I'm able to filter the List but not really sure how to update the UI when a user press a either button so I would be really appreciated if I can get any help or suggestion.
Right now, I just called one function in my FutureBuilder and not sure how to modify it.
class _SawnawkScreenState extends State<SawnawkScreen> {
#override
Widget build(BuildContext context) {
bool isSwitched = false;
return Scaffold(
body: FutureBuilder(
future: SortbyNumber(), // Need to do something here
builder: (context, data) {
if (data.hasError) {
return Center(child: Text("${data.error}"));
} else if (data.hasData) {
var items = data.data as List<SawnAwkModel>;
return ListView.builder(
itemCount: items == null ? 0 : items.length,
itemBuilder: (context, index) {
return SawnawkCardWidget(
id: items[index].id!,
);
});
} else {
return Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: SpeedDial(
children: [
SpeedDialChild(
child: Icon(Icons.sort_by_alpha_outlined),
backgroundColor: Colors.white,
label: 'Sort by alphabet',
onTap: () => {
print('sort by alphabet'),
//Do something here
}),
SpeedDialChild(
child: Icon(Icons.sort_by_number),
backgroundColor: Colors.white,
label: 'Sort by number',
onTap: () => {
print('sort by number'),
//Do something here
}),
],
),
);
}
}
Future<List<SawnAwkModel>> SortbyNumber() async {
final jsondata =
await rootBundle.rootBundle.loadString('assets/data/sawnawk_data.json');
final list = json.decode(jsondata) as List<dynamic>;
return list.map((e) => SawnAwkModel.fromJson(e)).toList();
}
Future<List<SawnAwkModel>> SortbyAlphabet() async {
final jsondata =
await rootBundle.rootBundle.loadString('assets/data/sawnawk_data.json');
final list = json.decode(jsondata) as List<dynamic>;
List<SawnAwkModel> profileList =
list.map((e) => SawnAwkModel.fromJson(e)).toList();
profileList.sort((a, b) {
return a.titleFalam.toLowerCase().compareTo(b.titleFalam.toLowerCase());
});
return profileList;
}

In order to update the UI, the code that changes the UI must be in a setState({}) function. In your case, try this:
SpeedDialChild(
child: Icon(Icons.sort_by_alpha_outlined),
backgroundColor: Colors.white,
label: 'Sort by alphabet',
onTap: () => {
print('sort by alphabet'),
setState({
final sorted = await SortbyAlphabet()
//update widget contents with sorted value above
})
}),
Your current code if difficult to update the UI, I suggest storing the ListView.builder items in a variable accessible by the function you want to use to update the UI, and change the contents there, like this:
class _SawnawkScreenState extends State<SawnawkScreen> {
bool isSwitched = false;
List items = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: SortbyNumber(), // Need to do something here
builder: (context, data) {
if (data.hasError) {
return Center(child: Text("${data.error}"));
} else if (data.hasData) {
items.addAll(data.data as List<SawnAwkModel>);
return ListView.builder(
itemCount: items == null ? 0 : items.length,
itemBuilder: (context, index) {
return SawnawkCardWidget(
id: items[index].id!,
);
});
} else {
return Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: SpeedDial(
children: [
SpeedDialChild(
child: Icon(Icons.sort_by_alpha_outlined),
backgroundColor: Colors.white,
label: 'Sort by alphabet',
onTap: () async {
setState({
print('sort by alphabet'),
final newItems = await SortbyAlphabet();
items.clear();
items.addAll(newItems);
})
}),
SpeedDialChild(
child: Icon(Icons.sort_by_number),
backgroundColor: Colors.white,
label: 'Sort by number',
onTap: () async {
setState({
print('sort by number'),
final newItems = await SortbyNumber();
items.clear();
items.addAll(newItems);
})
}),
],
),
);
}
}
Future<List<SawnAwkModel>> SortbyNumber() async {
final jsondata =
await rootBundle.rootBundle.loadString('assets/data/sawnawk_data.json');
final list = json.decode(jsondata) as List<dynamic>;
return list.map((e) => SawnAwkModel.fromJson(e)).toList();
}
Future<List<SawnAwkModel>> SortbyAlphabet() async {
final jsondata =
await rootBundle.rootBundle.loadString('assets/data/sawnawk_data.json');
final list = json.decode(jsondata) as List<dynamic>;
List<SawnAwkModel> profileList =
list.map((e) => SawnAwkModel.fromJson(e)).toList();
profileList.sort((a, b) {
return a.titleFalam.toLowerCase().compareTo(b.titleFalam.toLowerCase());
});
return profileList;
}

Please refer to this https://stackoverflow.com/a/70202810/15215450 for example on ValueListenable Builder
Please refer to the below code
final ValueNotifier<List> items = ValueNotifier([]);
floatingActionButton: SpeedDial(
children: [
SpeedDialChild(
child: Icon(Icons.sort_by_alpha_outlined),
backgroundColor: Colors.white,
label: 'Sort by alphabet',
onTap: () => {
print('sort by alphabet'),
//Do something here
items.value.clear();
items.value = await SortbyAlphabet();
items.notifyListeners();
}),
SpeedDialChild(
child: Icon(Icons.sort_by_number),
backgroundColor: Colors.white,
label: 'Sort by number',
onTap: () => {
print('sort by number'),
//Do something here
items.value.clear();
items.value = await SortbyAlphabet();
items.notifyListeners();
}),
],
),
ValueListenableBuilder(
valueListenable: isSwitched,
builder: (context, snapshot, child) {
return ListView.builder(
itemCount: items.value == null ? 0 : items.value.length,
itemBuilder: (context, index) {
return SawnawkCardWidget(
id: items.value[index].id!,
);
});
}));

Try this
late Future<dynamic> _future;
#override
void initState() {
_future = getDoctors();
}
class _SawnawkScreenState extends State<SawnawkScreen> {
#override
Widget build(BuildContext context) {
bool isSwitched = false;
return Scaffold(
body: FutureBuilder(
future: _future, // Need to do something here
builder: (context, data) {
if (data.hasError) {
return Center(child: Text("${data.error}"));
} else if (data.hasData) {
var items = data.data as List<SawnAwkModel>;
return ListView.builder(
itemCount: items == null ? 0 : items.length,
itemBuilder: (context, index) {
return SawnawkCardWidget(
id: items[index].id!,
);
});
} else {
return Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: SpeedDial(
children: [
SpeedDialChild(
child: Icon(Icons.sort_by_alpha_outlined),
backgroundColor: Colors.white,
label: 'Sort by alphabet',
onTap: () => {
print('sort by alphabet'),
//Do something here
setState(() {. // call setstate to refresh futurebuilder
_future = SortbyAlphabet();
}),
}),
SpeedDialChild(
child: Icon(Icons.sort_by_number),
backgroundColor: Colors.white,
label: 'Sort by number',
onTap: () => {
print('sort by number'),
//Do something here
}),
],
),
);
}
}
Future<List<SawnAwkModel>> SortbyNumber() async {
final jsondata =
await rootBundle.rootBundle.loadString('assets/data/sawnawk_data.json');
final list = json.decode(jsondata) as List<dynamic>;
return list.map((e) => SawnAwkModel.fromJson(e)).toList();
}
Future<List<SawnAwkModel>> SortbyAlphabet() async {
final jsondata =
await rootBundle.rootBundle.loadString('assets/data/sawnawk_data.json');
final list = json.decode(jsondata) as List<dynamic>;
List<SawnAwkModel> profileList =
list.map((e) => SawnAwkModel.fromJson(e)).toList();
profileList.sort((a, b) {
return a.titleFalam.toLowerCase().compareTo(b.titleFalam.toLowerCase());
});
return profileList;
}

Related

LateInitializationError error in flutter_map

I set up flutter_map succesfully, but when I try to filter my map by "City" for example I am getting this error:
The following LateError was thrown building FutureBuilder<List<dynamic>>(dependencies: [MediaQuery],
state: _FutureBuilderState<List<dynamic>>#cb20d):
LateInitializationError: Field '_state' has already been initialized.
The relevant error-causing widget was:
FutureBuilder<List<dynamic>>
My flutter_map implementation is as follow:
late MapController mapController;
Future<List<dynamic>>? futureLocs;
Future<List<dynamic>>? futureLocsFilteredByCity;
bool? isFilterByCity;
PageController pageController = PageController();
double currentZoom = 10.0;
PanelController panelController = PanelController();
#override
void initState() {
super.initState();
mapController = MapController();
pageController = PageController(viewportFraction: 0.7, initialPage: 0);
futureLocs = getAllDogsLocation();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: GenericAppBar(context,
backbutton: true,
title: 'Dogs map',
filterbutton: true, onfilterpress: () {
showDialog(
context: context,
builder: (context) {
return CitiesToFilter(
futureLocs: futureLocs,
onCityPress: (city) {
setState(() {
isFilterByCity = true;
futureLocs = getDogLocationByCity(city);
futureLocs!.then((value) {
if (value.isNotEmpty) {
var latlong = LatLng(
value[0]['latitude'], value[0]['longitude']);
widget.lat = latlong.latitude;
widget.long = latlong.longitude;
}
});
});
});
});
}),
body: FlutterMapCusto(
futureLocs: futureLocs,
mapController: mapController,
pageController: pageController,
lat: widget.lat,
long: widget.long,
panelcontroller: panelController,
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
heroTag: Text('CurrentLoc'),
onPressed: () {
setState(() {
mapController.move(
LatLng(widget.lat, widget.long), currentZoom);
});
},
tooltip: 'Current location',
child: const Icon(Icons.location_history),
),
],
));
}
}
where FlutterMapCusto widget is defined as a normal widget with FlutterMap class. I am not including it to avoid boilerplate code here since it is a basic implementation found in the package web. I think the error is coming from mapController..
On the other hand I am fetching my new data filtered by city with the function "getDogLocationByCity(city)" updating my future.
Then we have CitiesToFilter widget:
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Filter'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Filter by City'),
FloatingActionButton(onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Cities:'),
content: SizedBox(
width: MediaQuery.of(context).size.width,
child: FutureBuilder(
future: widget.futureLocs,
builder: (BuildContext context,
AsyncSnapshot<List<dynamic>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Text('Loading...');
case ConnectionState.active:
{
return const Center(
child: Text('Loading...'),
);
}
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'Error: ${snapshot.error}');
}
if (snapshot.hasData) {
return ListView.builder(
itemCount:
snapshot.data!.length,
itemBuilder: (context, index) {
return TextButton(
onPressed: () {
setState(() {
widget.onCityPress( snapshot.data![index]['CityName'] );
});
Navigator.pop(context);
},
child: Text(
snapshot.data![index]
['CityName']));
});
} else {
return const Text(
'No data available');
}
}
},
),
),
);
});
})
],
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Close'))
],
);
}
Future method to fetch the data shown in map. This is just a wrapper developed from Back4App to interact with its MongoDb database:
Future<List<dynamic>> getAllDogsLocation() async {
await Future.delayed(const Duration(seconds: 2), () {});
QueryBuilder<ParseObject> queryTodo =
QueryBuilder<ParseObject>(ParseObject('Todo'));
// queryTodo.includeObject(['latitude']);
final ParseResponse apiResponse = await queryTodo.query();
if (apiResponse.success && apiResponse.results != null) {
return apiResponse.results as List<ParseObject>;
} else {
throw Exception('Failed to load data');
}
}

Flutter fetch nested future

I have a method that fetches a PatientLog from SQLite.However, This PatientLog table mapped to an object with a class named PatientLog. Inside this PatientLog class, several other objects such as Speciality, AttendingPhysician, Course, etc. I need to map these PatienLog records to a local object. However, I have to use nested Futures. I need to retrieve the data from this nested Future. Think of Future of Future.
This is my fetch method
Future<List<Future<PatientLog>>> getForms() async {
Database db = await instance.getDatabase;
List<Map<String, dynamic>> forms =
await db.query(_tablePatientLog, orderBy: 'id DESC');
Institute? institute;
AttendingPhysician? attendingPhysician;
Speciality? speciality;
Course? course;
List<Future<PatientLog>> list = forms.map((myMap) async {
int? courseId = myMap['course_id'] as int?;
int? specialityId = myMap['speciality_id'] as int?;
int? attendingId = myMap['attending_id'] as int?;
int? instituteId = myMap['institute_id'] as int?;
if (courseId != null) {
await getCourse(courseId).then((value) => course=value);
}
if (attendingId != null) {
await getAttending(attendingId).then((value) => attendingPhysician=value);
}
if (specialityId != null) {
await getSpeciality(specialityId).then((value) => speciality=value);
}
if (instituteId != null) {
await getInstitute(instituteId).then((value) => institute=value);
}
return PatientLog.fromMap(
myMap, institute, course, attendingPhysician, speciality);
}).toList();
return list;
}
I need to display that information on a screen. I get an error type 'List<Future<PatientLog>>' is not a subtype of type 'Future<Object?>?'
class _DraftsState extends State<Drafts> {
final SQFLiteHelper _helper = SQFLiteHelper.instance;
#override
void initState() {
super.initState();
_refresh();
}
late List<Future<PatientLog>> fromDatabase;
Future<dynamic> _refresh() async {
await _helper.getForms().then((value) async{
setState(() {
fromDatabase = value;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _helper.getForms(),
builder: (BuildContext context,
AsyncSnapshot snapshot) {
if (snapshot.hasData && snapshot.data!.isEmpty) {
return Center(
child: Text(
"Henüz kaydedilmiş taslak bulunmamaktadır.",
textAlign: TextAlign.center,
style: TEXT_STYLE,
));
}
if (snapshot.hasError) {
return Center(
child: Text(
'Sanırım bir şeyler ters gitti.',
style: TEXT_STYLE,
));
}
if (snapshot.connectionState == ConnectionState.done) {
return RefreshIndicator(
backgroundColor: Colors.grey[700],
color: LIGHT_BUTTON_COLOR,
onRefresh: _refresh,
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: ListView.builder(
shrinkWrap: true,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
return FutureBuilder(
future: snapshot.data,
builder: (context,innerSnap) {
return Text(innerSnap.toString());/*CustomListTile(
formData: innerSnap.data[index],
index: index,
routeTo: 1,
isDeletable: true,
);*/
}
);
},
),
),
);
}
return const Center(
child: Text("Nothing")//spinkit,
);
}),
);
}
}

Flutter cannot increment inside listtile, always returning 0

I want to increment number on trailing ListTile Flutter when ontap ListTile,
but always return to 0?
i'm using future builder fyi,
thanks in advance
this my model
class ItemModel {
String name;
String price;
String image;
bool isSelected = false;
int countSelected = 0;
ItemModel(
this.name,
this.price,
this.image,
);
}
This method to get data from api json from local server
Future<List<ItemModel>> _getItems() async {
List<ItemModel> listItems = [];
var url = Uri.parse(BASEURLLOCAL.apiGetItems);
var data = await http.get(url);
var jsonData = jsonDecode(data.body);
for (var p in jsonData) {
ItemModel item = ItemModel(
p["name"],
p["price"],
p["image"],
// p["PRODUCT_NAME"],
// p["PRICE_SELL"],
// p["FILENAME"],
);
listItems.add(item);
}
return listItems;
}
and this the listview builder
#override
Widget build(BuildContext context) {
return FutureBuilder<List<ItemModel>>(
future: _getItems(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
} else {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext contex, int idx) {
if (_itemCount.length < snapshot.data.length) {
_itemCount.add(0);
}
return Card(
child: ListTile(
leading: Image.network(
BASEURLLOCAL.imgItem + snapshot.data[idx].image),
title: Text(snapshot.data[idx].name),
subtitle: Text(snapshot.data[idx].price),
// trailing: _buildTrailing(),
trailing: Text(snapshot.data[idx].countSelected.toString()),
onTap: () {
setState(() {
snapshot.data[idx].countSelected++;
});
},
),
);
},
);
}
},
);
}
this is what the problem is
Try something like this, create a list
List<ItemModel> listItems = [];
then, in initState() call the _getItems()
_getItems() async {
var url = Uri.parse(BASEURLLOCAL.apiGetItems);
var data = await http.get(url);
var jsonData = jsonDecode(data.body);
for (var p in jsonData) {
ItemModel item = ItemModel(
p["name"],
p["price"],
p["image"],
// p["PRODUCT_NAME"],
// p["PRICE_SELL"],
// p["FILENAME"],
);
listItems.add(item);
}
}
And remove FutureBuilder
#override
Widget build(BuildContext context) {
return ListView.builder(
shrinkWrap: true,
itemCount: listItems.length,
itemBuilder: (BuildContext context, int idx) {
if (_itemCount.length < listItems.length) {
_itemCount.add(0);
}
return Card(
child: ListTile(
leading: Image.network(BASEURLLOCAL.imgItem + listItems[idx].image),
title: Text(listItems[idx].name),
subtitle: Text(listItems[idx].price),
// trailing: _buildTrailing(),
trailing: Text(listItems[idx].countSelected.toString()),
onTap: () {
setState(() {
listItems[idx].countSelected++;
});
},
),
);
},
);
}
By this way it won't fetch everytime when it rebuilds.

how to CupertinoSwitch dynamically(Map) value set in flutter?

Creating dynamic list(request), I put a switch in there.
However, the switches refuse to show their intended state (The status does not change when clicked.)
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:scat/request.dart' as request;
import 'package:scat/util.dart' as util;
class _ConfigPushState extends State<ConfigPush> {
Future<request.ApiResult> configList;
Map<String, bool> _onOffMap = {};
#override
void initState() {
super.initState();
configList = request.configList();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50.0), // here the desired height
child: new AppBar(
backgroundColor: Colors.black,
leading: new IconButton(
icon: new Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
),
centerTitle: true,
title: new Text('API 설정', style: util.appTitleStyle),
),
),
body: Center(
child: FutureBuilder<request.ApiResult>(
future: configList,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return CircularProgressIndicator();
}
_onOffMap = {};
return ListView.separated(
separatorBuilder: (context, index) => Divider(),
itemCount: snapshot.data.data.length,
itemBuilder: (context, index) {
var row = snapshot.data.data[index];
var type = row['type'] as String;
var value = row['value'] as bool;
var disabled = row['isDisabled'] as bool;
var subtitle = disabled ? '아직 준비중' : row['description'];
_onOffMap[type] = value;
// _arr.add(value);
// _lights = value;
print('item builder ${type}');
return Container(
height: util.isEmpty(subtitle) ? 50 : 70,
child: new ListTile(
title: new Text(row['name']),
subtitle: new Text(subtitle),
trailing: CupertinoSwitch(
activeColor: Colors.deepPurple,
// value: _arr[index],
// value: _lights,
value: _onOffMap[type],
onChanged: (bool value) {
setState(() {
if (disabled) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('개발중..')));
return;
}
// _lights = value;
print("before $_onOffMap $type");
_onOffMap[type] = value;
print("after $_onOffMap");
request
.pushSet(type, value.toString(), "", "")
.then((a) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('처리 되었습니다.')));
});
});
},
),
));
});
})),
);
}
}
try this one I hope it work for you:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:scat/request.dart' as request;
import 'package:scat/util.dart' as util;
class _ConfigPushState extends State<ConfigPush> {
Future<request.ApiResult> configList;
Map<String, bool> _onOffMap = {};
#override
void initState() {
super.initState();
configList = request.configList();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50.0), // here the desired height
child: new AppBar(
backgroundColor: Colors.black,
leading: new IconButton(
icon: new Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
),
centerTitle: true,
title: new Text('API 설정', style: util.appTitleStyle),
),
),
body: Center(
child: FutureBuilder<request.ApiResult>(
future: configList,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return CircularProgressIndicator();
}
_onOffMap = {
"type": true;
};
return ListView.separated(
separatorBuilder: (context, index) => Divider(),
itemCount: snapshot.data.data.length,
itemBuilder: (context, index) {
var row = snapshot.data.data[index];
var type = row['type'] as String;
var value = row['value'] as bool;
var disabled = row['isDisabled'] as bool;
var subtitle = disabled ? '아직 준비중' : row['description'];
_onOffMap["type"] = value;
// _arr.add(value);
// _lights = value;
print('item builder ${type}');
return Container(
height: util.isEmpty(subtitle) ? 50 : 70,
child: new ListTile(
title: new Text(row['name']),
subtitle: new Text(subtitle),
trailing: CupertinoSwitch(
activeColor: Colors.deepPurple,
// value: _arr[index],
// value: _lights,
value: _onOffMap["type"],
onChanged: (bool value) {
setState(() {
if (disabled) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('개발중..')));
return;
}
// _lights = value;
print("before $_onOffMap $type");
_onOffMap["type"] = value;
print("after $_onOffMap");
request
.pushSet(type, value.toString(), "", "")
.then((a) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('처리 되었습니다.')));
});
});
},
),
));
});
})),
);
}
}

Flutter - StreamBuilder - Refresh

I have a StreamBuilder inside my Widget build of UserListDart:
StreamBuilder(
stream: stream.asStream(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData) {
return Expanded(
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
snapshot.data[index].firstname + " " +
snapshot.data[index].lastname
),
onTap: () {
Navigator.of(context).push(DetailScreenDart(snapshot.data[index]));
},
);
}
)
);
}
}
...
)
The Stream is defined in the initState:
Future<List> stream;
#override
void initState() {
super.initState();
stream = fetchPost();
}
The fetchPost() is an api call:
Future<List<User>> fetchPost() async {
final response = await http.get('url');
final jsonResponse = json.decode(response.body);
List<User> users = [];
for(var u in jsonResponse){
User user = User(
firstname: u["firstname"],
lastname: u["lastname"],
);
users.add(user);
}
return users;
}
I Navigate to another Page to change for example the firstname (api get updated) and I Navigate back to the UserList:
Navigator.pushReplacement(
context,
new MaterialPageRoute(builder: (context) => new UserListDart())
).then((onValue) {
fetchPost();
});
But the StreamBuilder won't get updated and I don't know why.
Note:
I think the StreamBuilder don't realise that a change has happend when I navigate back. It only applies the changes if I reopen the Page..
You should be using setState and updating your stream variable with the result of the fetchList() call:
Navigator.pushReplacement(
context,
new MaterialPageRoute(builder: (context) => new UserListDart())
).then((onValue) {
setState((){
stream = fetchPost();
});
});
Here's a working example of what you want to achieve:
class StreamBuilderIssue extends StatefulWidget {
#override
_StreamBuilderIssueState createState() => _StreamBuilderIssueState();
}
class _StreamBuilderIssueState extends State<StreamBuilderIssue> {
Future<List<String>> futureList;
List<String> itemList = [
'item 1',
'item 1',
'item 1',
'item 1',
'item 1',
];
#override
void initState() {
futureList = fetchList();
super.initState();
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Center(
child: StreamBuilder(
stream: futureList.asStream(),
builder: (context, snapshot){
if(snapshot.hasData){
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index){
return Text(snapshot.data[index]);
},
);
}else{
return CircularProgressIndicator();
}
},
),
),
),
RaisedButton(
onPressed: goToAnotherView,
child: Text('Next View'),
),
RaisedButton(
onPressed: addItem,
child: Text('AddItem'),
)
],
),
);
}
Future<List<String>> fetchList(){
return Future.delayed(Duration(seconds: 2), (){
return itemList;
});
}
void goToAnotherView(){
Navigator.push(context, MaterialPageRoute(
builder: (context){
return StreamBuilderIssueNewView(addItem);
})
).then((res){
setState(() {
futureList = fetchList();
});
});
}
void addItem(){
itemList.add('anotherItem');
}
}
class StreamBuilderIssueNewView extends StatelessWidget {
final Function buttonAction;
StreamBuilderIssueNewView(this.buttonAction);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
children: <Widget>[
Text('New view'),
RaisedButton(
onPressed: buttonAction,
child: Text('AddItem'),
)
],
),
),
);
}
}
By the way, you could also just use a FutureBuilder as your are not using a real Stream here, just an api fetch and you have to update with setState anyway.