Flutter Application showing blank screen when trying to invoke a Future Builder - flutter

I am trying to build a futureBuilder with a Future Function that I have which passes through a list of objects which contain the surveyName parameter, I am trying to display that surveyName descriptor into a listView but am noticing that I am getting a blank white screen that isn't showing both the container which is just supposed to show some basic loading functionality and it isn't displaying the information of the getSurveys function either.
I am new to both dart and flutter, so this may just have some basic simple resolution but any information would be helpful. The method getSurveys below in the print displays both names in the print so I know the information is coming in correct for that specific function but I am wondering why it isn't working within the futureBuilder.
The 1 and 2 print statements are running but I am noticing the 3 print statement isn't so that listView Builder is not being invoked for some starnge reason, which may be the cause of this dilemma but I wonder why the container which is just supposed to showcase a loading... is not working correctly either. Output is below this function.
Future<List<Survey_List>> getSurveys() async{
Map map = {
'Type': "getSurveys"
};
var _list = [];
List<Survey_List> surveys = [];
getPost(map).then((Map value){
_list.addAll(value["survey"]);
for (int i = 0; i < _list.length; i++){
Survey_List survey_list = Survey_List(surveyName: _list[i].toString() ,surveyDescription: "", surveyVersion: "");
surveys.add(survey_list);
print(survey_list.surveyName);
}
});
return surveys;
}
Output is as follows:
I/flutter ( 2020): 2
I/flutter ( 2020): 1
I/flutter ( 2020): {"survey":["Survey","Surve3ww"]}
I/flutter ( 2020): Survey
I/flutter ( 2020): Surve3ww
import 'dart:convert';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter_application/Http.dart';
import 'Config.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Survey_List extends StatefulWidget {
String surveyName;
String surveyDescription;
String surveyVersion;
Survey_List({
this.surveyName,
this.surveyDescription,
this.surveyVersion,
Key key,
}) : super (key: key);
#override
_SurveyListState createState() => _SurveyListState();
}
class _SurveyListState extends State<Survey_List> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Surveys"),
),
body: new Container(
child: new FutureBuilder <List<Survey_List>>(
future: getSurveys(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
List<Survey_List> surveys = snapshot.data;
if (snapshot.hasData) {
print(1);
return new ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
print(3);
Survey_List survey_list = surveys[index];
print(survey_list.toString());
return new ListTile(
title: new Text(survey_list.surveyName)
);
},
);
}
else{
print(2);
return new Container(
child: new Center(
child: new Text("Loading...")
)
);
}
},
),
),
);
}
}

Related

How to use ListView with the data of REST API with Flutter using Obx?

import 'dart:convert';
import 'package:get/get.dart';
import '../../../functions/functions.dart';
import '../models/user_details_modal.dart';
class UserListController extends GetxController {
var data = [];
List<UserDetails> userDetails = <UserDetails>[].obs;
// var userDetails = <UserDetails>[].obs;
// RxList<UserDetails> userDetails = <UserDetails>[].obs;
// RxList<UserDetails> userDetails = RxList();
Future<void> fetchData() async {
String apipage = "getData.php";
Map mappeddata = {};
final response = await sendServerData(apipage, mappeddata);
if (response.statusCode == 200) {
final responseBody = jsonDecode(response.body.toString());
userDetails = userDetailsFromJson(json.encode(responseBody));
print(userDetails);
update();
} else {
Get.snackbar(
'Server Connection Failed', 'Please try again after some time');
}
}
#override
void onInit() {
fetchData();
super.onInit();
}
}
Above code is my controller,
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/user_list_controller.dart';
import '../models/user_details_modal.dart';
class UserListView extends GetView<UserListController> {
#override
final UserListController controller = Get.put(UserListController());
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ListView'),
centerTitle: true,
),
body: Obx(
() => controller.userDetails.isEmpty
? Center(
child: Text("Loading data..."),
)
: ListView.builder(
itemCount: controller.userDetails.length,
itemBuilder: (context, index) {
final UserDetails item = controller.userDetails[index];
return buildListTile(item);
},
),
),
);
}
Widget buildListTile(UserDetails item) {
print("userName: ${item.userName}");
print("userEmail: ${item.userEmail}");
return ListTile(
title: Text(item.userName),
subtitle: Text(item.userEmail),
trailing: IconButton(
icon: const Icon(Icons.edit),
onPressed: () {},
),
);
}
}
This is my view,but it's throwing this error -
"[Get] the improper use of a GetX has been detected.
You should only use GetX or Obx for the specific widget that will be updated.
If you are seeing this error, you probably did not insert any observable variables into GetX/Obx
or insert them outside the scope that GetX considers suitable for an update
(example: GetX => HeavyWidget => variableObservable).
If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX."
i'm a beginner in flutter,so please help me to find the issue here.
I have updated the code,i made some changes in controller part declaring that List,now that prev issue is solved!
But the problem is no data showing up on first load (using Get.to() to navigate to this from another page) but when i hot reload/reload this page it shows those data.
What's the problem?
if you want to use reactive approach using Obx() or Getx(), you need to make your variables observable. You can do this simply by adding .obs to the variable. This makes your variables as Rx type.
There are other ways to make your variables observable, but this is the simplest one.
in the controller:
var data = [].obs;
List<UserDetails> userDetails = [].obs;
Also, you don't need to use update() for this approach.
And whenever you want to change the value or use it in your view
you should access the value like this.
in the view inside the Obx: ( in the code above, no need to use .value for the list)
E.x)
bool isLoading = controller.loading.value
Hope this helped :)

Trouble initializing a <Position> variable in Flutter LateInitializationError: Field '____ ' has not been initialized

newbie to Flutter. My code runs but encounters a
The following LateError was thrown building
FutureBuilder(dirty, state:
_FutureBuilderState#e1a6f):
LateInitializationError: Field 'initialPosition' has not been
initialized.
The code is to set up a GoogleMap widget that takes initial position from the device. I get the red screen with that error, but after a few seconds the coordinates gets received and proceeds as normal and displays the map and position correctly.
Tried future as well but but I get other errors. Is it supposed to be under the FutureBuilder? In a wrapper.dart or my main.dart?
home.dart:
import 'package:flutter/material.dart';
import 'package:something/services/auth.dart';
import 'screens/map.dart';
import 'package:something/services/geolocator_service.dart';
class LakoApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<LakoApp> {
final AuthService _auth = AuthService();
final _geolocatorService = GeolocatorService();
late var initialPosition;
// #override
Future getInitialPosition <Position>() async {
initialPosition = await _geolocatorService.getInitialLocation();
return initialPosition;
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: FittedBox(
child: Text('Something something'),
),
actions: <Widget>[
// irrelevant code
// .....
],
body:
FutureBuilder(
future: getInitialPosition(),
builder: (context, snapshot) {
return Map(initialPosition);
}
)
);
}
}
Future Builders are built even before getting the data. So, you should check whether it has data.
if (snapshot.hasData) {
return Map(initialPosition); //Or snapshot.data.
}else{
return CircularProgressIndicator();
}
There are other problems here. I will show some further code to improve your own code.
Your method returns a Future of any type receiving a generic parameter called Position. I think you want to use a data type called position for that you need to move <Position> here as right now the way you are writing it is useless for your specific example.
Future<Position> getInitialPosition () async {
initialPosition = await _geolocatorService.getInitialLocation();
return initialPosition;
}
The FutureBuilder can be like this.
FutureBuilder<Position>(
future: getInitialPosition(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Map(snapshot.data);
}else{
return CircularProgressIndicator();
//Display loading, you may adapt this widget to your interface or use some state management solution
}
}
)
Edited the code according to suggestions: got rid of the method and variable, because its redundant
body: FutureBuilder <Position> (
future: _geolocatorService.getInitialLocation(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Map(snapshot.data!);
}else {
return Loading();

What is "dirty" in Flutter & what is causing this "dirty" state?

I am trying to learn both state management & dependancy injection with this demo project. I'm trying to demo injecting some methods all over the place like I may need to in my program. I'm using GetX because I like being able to do this without context in non-widget classes.
So my problem here is the last method, summationReturns(), in the last class below. Attempts to take methods with return statements and add them together. I call this in two places. In the floating button, this works fine but in my text widget I get a dirty state error.
Why is this not working when everything else works? And I assume this will be a corollary from the last question, what is a dirty state? Seems like two questions but I would imagine that they are one in the same.
///
///
/// DEMO PROJECT WORKING OUT GETX
/// WORKOUT DEPENDANCY INJECTION AND STATE MANAGEMENT
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_state_manager/get_state_manager.dart';
void main() {
runApp(GetMaterialApp(
home: Home(),
debugShowCheckedModeBanner: false,
));
}
class Home extends StatelessWidget {
// Injection of dependancy
final Controller controller = Get.put(Controller());
final Observable observable = Get.put(Observable());
final SimpleMath simpleMath = Get.put(SimpleMath());
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GetX Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Get builders:'),
GetBuilder<Controller>(builder: (controller) {
return Text(controller.count.toString());
}),
GetBuilder<Controller>(builder: (controller) {
return Text(controller.countList.toString());
}),
GetBuilder<Controller>(builder: (controller) {
return Text(controller.returnCount().toString());
}),
GetBuilder<Controller>(builder: (controller) {
return Text(controller.returnList().toString());
}),
SizedBox(height: 20.0),
Text('Get observables:'),
Obx(() => Text(observable.count.value.toString())),
Obx(() => Text(observable.countList.value.toString())),
Obx(() => Text(observable.returnCount().toString())),
Obx(() => Text(observable.returnList().toString())),
SizedBox(height: 20.0),
Text('Get from other class:'),
GetBuilder<SimpleMath>(builder: (simpleMath) {
return Text('Variable summation: ' + simpleMath.summationVariables().toString());
}),
GetBuilder<SimpleMath>(builder: (simpleMath) {
return Text(simpleMath.summationReturns().toString());
}),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
controller.crunch();
observable.crunch();
simpleMath.summationVariables();
simpleMath.summationReturns();
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class Controller extends GetxController {
int count = 0;
List<int> countList = [];
void crunch() {
count += 1;
countList.add(count);
update();
}
int returnCount() {
return count;
}
List<int> returnList() {
return countList;
}
}
class Observable extends GetxController {
RxInt count = 0.obs;
Rx<RxList> countList = RxList().obs;
void crunch() {
count.value += 1;
countList.value.add(count.value);
}
int returnCount() {
return count.value;
}
List<dynamic> returnList() {
return countList.value.toList();
}
}
class SimpleMath extends GetxController {
final Controller controller = Get.find<Controller>();
final Observable observable = Get.find<Observable>();
int summationVariables() {
int sum = controller.count + observable.count.value;
update();
return sum;
}
int summationReturns() {
int sum = controller.returnCount() + observable.returnCount();
print('Summation of return values: ' + sum.toString());
update();
return sum;
}
}
Error:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building GetBuilder<SimpleMath>(dirty, state:
GetBuilderState<SimpleMath>#4d62d):
setState() or markNeedsBuild() called during build.
This GetBuilder<SimpleMath> widget cannot be marked as needing to build because the framework is
already in the process of building widgets. A widget can be marked as needing to be built during
the build phase only if one of its ancestors is currently building. This exception is allowed
because the framework builds parent widgets before children, which means a dirty descendant will
always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
GetBuilder<SimpleMath>
The widget which was currently being built when the offending call was made was:
GetBuilder<SimpleMath>
The relevant error-causing widget was:
GetBuilder<SimpleMath>
file:///Users/robertobuttazzoni/Documents/Flutter%20Tutorials/Flutter%20Learning/getx_basics/getx_basics/lib/main.dart:57:13
Calling update while build is ongoing is an example of dirty scenario. To fix your issue, do not call update inside the GetBuilder.
Sample...
In Home
GetBuilder<SimpleMath>(
builder: (simpleMath) => Text('Variable summation: ' +
simpleMath
.summationVariables(shouldUpdate: false)
.toString())),
GetBuilder<SimpleMath>(
builder: (simpleMath) => Text(simpleMath
.summationReturns(shouldUpdate: false)
.toString())),
In SimpleMath
int summationVariables({bool shouldUpdate = true}) {
int sum = controller.count + observable.count.value;
if (shouldUpdate) update();
return sum;
}
int summationReturns({bool shouldUpdate = true}) {
int sum = controller.returnCount() + observable.returnCount();
print('Summation of return values: ' + sum.toString());
if (shouldUpdate) update();
return sum;
}

Why doesn't the UI in Flutter's SpannableGrid widget refresh to update with latest content from stream of String?

WallStream class gives me a stream of string that is incremented every 1 second as the app runs
I'm using the spannable_grid from https://pub.dev/packages/spannable_grid. Whenever the stream content change, I'm expecting _buildData to also change (which it does, due to the printed value on line 27). I then add a new SpannableGridCellData with the updated content to a list and return a new SpannableGrid widget based on the updated cells. I expect the UI to change to show the new content but it doesn't. Why not?
pubspec.yaml
spannable_grid: ^0.1.3
provider: ^3.1.0
main.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:spannable_grid/spannable_grid.dart';
void main() => runApp(MaterialApp(home: WallPane()));
class WallPane extends StatefulWidget {
#override
_WallPaneState createState() => _WallPaneState();
}
class _WallPaneState extends State<WallPane> {
#override
Widget build(BuildContext context) {
return StreamProvider<String>.value(
value: WallStream.instance.wallStateStream,
child: new LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return _buildData(context, constraints);
}));
}
Widget _buildData(BuildContext context, BoxConstraints constraints) {
String content = Provider.of<String>(context);
print(content);
List<SpannableGridCellData> cells = List();
cells.add(SpannableGridCellData(
column: 1,
row: 1,
columnSpan: 2,
rowSpan: 2,
id: content,
child: Container(
color: Colors.lime,
child: Center(
child: Text(content),
),
),
));
return SpannableGrid(
columns: 4,
rows: 4,
cells: cells,
spacing: 2.0,
onCellChanged: (cell) {
print('Cell ${cell.id} changed');
},
);
}
}
class WallStream {
static int _counter = 0;
Stream<String> get wallStateStream async* {
while (true) {
yield (_counter++).toString();
await Future.delayed(Duration(seconds: 1));
}
}
WallStream._privateConstructor();
static final WallStream instance = WallStream._privateConstructor();
}
I also looked up the source code here (https://raw.githubusercontent.com/ech89899/spannablegrid-flutter/master/lib/spannable_grid.dart - I don't think it's updated with the latest code yet but I tried to use the code seen on the repo and have the same problem). I don't understand why performLayout in class _SpannableGridDelegate extends MultiChildLayoutDelegate is called whenever I see the stream data change but the cell.Child doesn't have the latest data.
Please help. Thank you in advance.
I am author of SpannableGrid package. Thank you for using it, and for the feedback provided.
There was a bug in the package. I've added a fix for this. Please check if the version 0.1.4+ will work for you.

How to display data of firestore DocumentReference in flutter

I got two collection in my firestore database and It's structure like,
Collection1 - movies
-movieTitle : String
-movieYear : String
-movieDirector : DocumentReference
.
.
etc
Collection2 - directors
-dirName: String
-dirImage: String
.
.
etc
I want to display movieTitle and dirName in a ListTile.
Here how I have tried to do so,
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _TestPageState();
}
}
class _TestPageState extends State<TestPage> {
DocumentSnapshot document;
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('movies').snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> movieSnapshot) {
if (!movieSnapshot.hasData) return const Text('Loading...');
final int messageCount = movieSnapshot.data.documents.length;
return ListView.builder(
itemCount: messageCount,
itemBuilder: (_, int index) {
document = movieSnapshot.data.documents[index];
return ListTile(
title: Text(document['movieTitle'] ?? 'title not retrieved'),
subtitle: Text(getValue(document["movieDirector"]) ??
'director not retrieved'),
);
},
);
},
),
);
}
String getValue(DocumentReference documentReference) {
String val;
documentReference.get().then((onData) {
val = onData.data["directorName"];
print(val);
});
return val;
}
}
Finally I couldn't be able to get the value on screen. What should I change in my implementation?
You need to learn about Futures and async/await so you can comfortably write such code.
The problem here is that getValue has to return immediately, but the directorName that it asks arrives sometime in the future. Therefore you simply can't get it right now.
Giving a FutureBuilder to the subtitle: is one of the options you can pursue.
Also you should consider caching the stream (and the future, if you implement it as per my suggestion above) so that you do not make unwanted requests. Right here I try to explain it in a presentation of mine: https://youtu.be/0gBsHLgCY6M?list=PL0bBHyAilexzBdvHookPcPZNMceciAaZf&t=1900