Adding data to existing list from initState in Flutter (Async) - flutter

I try to load specific data from my Sembast database to the view on init and add it to an existing list. Why this code does not work?
The data exists, but could it be that my code will never called? I´ve edited the code with print. print("3") does not fire.
bool _checkConfiguration() => true;
#override
void initState() {
_currentDate = widget._currentDate;
_markedDateMap = widget._markedDateMap;
if (_checkConfiguration()) {
print("1"); // FIRES
Future.delayed(Duration(seconds: 2), () {
final calendarEntriesDataInitial =
Provider.of<CalendarEntries>(context, listen: false);
print("2"); // FIRES
FutureBuilder<List<CalendarEntry>>(
future: calendarEntriesDataInitial.getAll(),
builder: (BuildContext context,
AsyncSnapshot<List<CalendarEntry>> snapshot) {
print("3"); // NOT FIRES. HERE´S A PROBLEM!
if (snapshot.hasData &&
snapshot.connectionState != ConnectionState.waiting) {
for (final entry in snapshot.data) {
setState(() {
_markedDateMap.add(
new DateTime(entry.dateTime),
new Event(
date: new DateTime(entry.dateTime),
title: 'Event 5',
icon: _eventIcon,
));
});
}
}
});
});
}
super.initState();
}

You have to use setState() for showing updated UI in map
setState(() {
_markedDateMap.add(...)
});

I found a solution: The FutureBuilder is a widget and can only by used in the widget three. Therefore I use another way to get my required values:
#override
void initState() {
_currentDate = widget._currentDate;
_markedDateMap = widget._markedDateMap;
Future.delayed(Duration.zero, () {
final calendarEntriesDataInitial =
Provider.of<CalendarEntries>(context, listen: false);
calendarEntriesDataInitial.getAll().then((value) {
if (value == null || value.isEmpty) {
return;
}
for (final entry in value) {
if (entry.dateTime != null) {
final date = DateTime.parse(entry.dateTime);
setState(() {
_markedDateMap.add(
new DateTime(date.year, date.month, date.day),
new Event(
date: new DateTime(date.year, date.month, date.day),
title: entry.servicePartner,
icon: _eventIcon,
));
});
}
}
});
});
super.initState();
}

Related

flutter - FutureBuilder auto rebuild each time press a button in the screen

I try to use FutureBuilder in Flutter to wait ulti my initState is finished then buil the UI for the app.
But when the app is running, the screen keep rebuilding each time I press another button (the button does totally different thing).
Future loadUser() async {
String jsonString = await storage.read(key: "jwt");
final jsonResponse = json.decode(jsonString);
loggedUser = new LoggedUser.fromJson(jsonResponse);
print(loggedUser.token);
getProfile();
getJourneyByUserId()
.then((receivedList){
addRanges(receivedList);});
}
Future<List<Journey>>getJourneyByUserId() async {
var res = await http.get(
Uri.parse("$baseUrl/journeys/userid=${loggedUser.user.userId}"),
headers: {
'Content_Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ${loggedUser.token}',
},
);
if (res.statusCode == 200) {
print("Get journeys successfully");
}
var data = jsonDecode(res.body);
List idList = [];
for (var i in data) {
idList.add(i["journeyId"]);
}
for (var i in idList) {
var res = await http.get(
Uri.parse("$baseUrl/journeys/$i"),
);
var data = jsonDecode(res.body);
Journey userJourney = new Journey.fromJson(data);
setState(() {
journeyList.add(userJourney);
});
}
print("Journey ${journeyList.length}");
return journeyList;
}
addRanges(journeyList){
setState(() {
rangeList=[];
});
if (journeyList.isNotEmpty) {
for (var i in journeyList) {
DateTime startDate =
DateTime(i.startDate.year, i.startDate.month, i.startDate.day);
DateTime endDate =
DateTime(i.endDate.year, i.endDate.month, i.endDate.day);
setState(() {
rangeList.add(PickerDateRange(startDate, endDate));
});
}
}
print("Range ${rangeList.length}");
return rangeList;
}
returnRange() {
List<PickerDateRange> list = [];
for(int i =0; i<rangeList.length;i++){
list.add(rangeList[i]);
}
return list;
}
Future functionForBuilder() async {
return await returnRange();
}
//initState function
#override
void initState() {
super.initState();
loadUser();
functionForBuilder();
}
//build the UI
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("$_name's Profile",style: TextStyle(color: kColorPalette4),),
centerTitle: true,
),
body: Container(
child: FutureBuilder(
future: functionForBuilder(),
builder: (BuildContext context,AsyncSnapshot snapshot){
//here I set the condition for each case of snapshot
}
I have read some documents say that I should assign the functionForBuilder() to a Future variable when initState then use it in the future child of FutureBuilder. Example:
Future _future;
//initState function
#override
void initState() {
super.initState();
loadUser();
_future=functionForBuilder();
}
// then with the FutureBuilder
future: _future
With this way the screen is not rebuild anymore but my function returnRange() seems like not running as my expextation (I called the returnRange() once in the build() function).
Thanks in advance for your answer!
Whenever you assign to the _future variable again, you must do that inside a setState block, otherwise the widget will not rebuild with the new future.
For example:
void updateData() {
setState(() {
_future = functionForBuilder();
});
}
If you use FutureBuilder, it rebuild items again and again.
Try two ways:
Don't use `future: functionForBuilder(), comment it.
Remove FutureBuilder(), simply use Container().
And let me know any issue?
Code:
call your future in the initstate method not in the build as shown in the example.
class MyPage extends StatefulWidget { #override State<MyPage> createState() => _MyPageState(); } class _MyPageState extends State<MyPage> { // Declare a variable. late final Future<int> _future; #override void initState() { super.initState(); _future = _calculate(); // Assign your Future to it. } // This is your actual Future. Future<int> _calculate() => Future.delayed(Duration(seconds: 3), () => 42); #override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<int>( future: _future, // Use your variable here (not the actual Future) builder: (_, snapshot) { if (snapshot.hasData) return Text('Value = ${snapshot.data!}'); return Text('Loading...'); }, ), ); } }

call one asynchronous function when the first one runs flutter

I have two asynchronous functions, one returns a popup, the other makes a permission request. I call them in the init method. But they are called simultaneously, i.e. the first window appears and immediately the second. How do I fix this?
class _MyAppState extends State<MyApp> {
final keyIsFirstLoaded = 'is_first_loaded';
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final context = MyApp.navKey.currentState.overlay.context;
await showDialogIfFirstLoaded(context);
await initPlatformState();
});
}
showDialogIfFirstLoaded(BuildContext context, prefs) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isFirstLoaded = prefs.getBool(keyIsFirstLoaded);
if (isFirstLoaded == null) {
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return new AlertDialog(
// title: new Text("title"),
content: new Text("//"),
actions: <Widget>[
new FlatButton(
child: new Text(".."),
onPressed: () {
Navigator.of(context).pop();
prefs.setBool(keyIsFirstLoaded, false);
},
),
],
);
},
);
}
}
initPlatformState() async {
print('Initializing...');
await BackgroundLocator.initialize();
print('Initialization done');
final _isRunning = await BackgroundLocator.isRegisterLocationUpdate();
setState(() {
isRunning = _isRunning;
});
onStart();
print('Running ${isRunning.toString()}');
}
add return to showDialog statement, you're not returning a Future so await isn't doing anything
Personal advice: always specify return types, cause if you don't, you get dynamic return type. If you do specify it, the IDE/dart analysis server will help you with problems such as this one.

Unhandled Exception: A Follows was used after being disposed.Once you have called dispose() on a Follows, it can no longer be used

I am new in state Management in flutter with provider package .
How many different cause for generate these types of exception and How can I fix it,
this exception was generate when getFollowing() method was called in didChangeDependencies.
Follows.dart
class Follows with ChangeNotifier{
List<Follow> _following =[];
String userid;
String token;
List<Follow> get followingUser{
return [..._following];
}
void updates(String token,String userid){
this.userid = userid;
this.token = token;
}
Future<void> getFollowing(String id) async {
final response = await http.get("${Domain.ADDRESS}/user/following/$id",headers: {"auth-token" : this.token});
final data =json.decode(response.body)["following"] as List;
List<Follow> followingData =[];
data.forEach((user){
followingData.add(Follow(
id: user["_id"],
username: user["username"],
fullname: user["fullname"],
imageUrl: user["imageUrl"],
followerCount : (user["followers"] as List).length
));
});
_following = [...followingData];
notifyListeners();
}
.........
}
Main.dart
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => Auth(),
),
ChangeNotifierProxyProvider<Auth , Follows>(
create: (ctx)=>Follows(),
update : (context, auth, previous) => Follows()..updates(auth.token, auth.userId)
),
]
child : .......
);
FollowList.dart
class FollowList extends StatefulWidget {
static const followRoutes = "/follow-list";
final String id;
FollowList({this.id});
#override
_FollowListState createState() => _FollowListState();
}
class _FollowListState extends State<FollowList> {
bool isLoading = false;
#override
void didChangeDependencies() {
setState(() {
isLoading = true;
});
Provider.of<Follows>(context,listen: false).getFollowing(widget.id).then((_){
setState(() {
isLoading = false;
});
});
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
List<Follow> following = Provider.of<Follows>(context,listen: false).followingUser;
return Scaffold(
appBar: AppBar(title: Text("following),),
body: isLoading ? Center(child: CircularProgressIndicator(strokeWidth: 1,))
: ListView.builder(
itemBuilder: (context, index) => UserCard(
id: following[index].id,
fullname :following[index].fullname,
username :following[index].username,
followerCount : following[index].followerCount,
imageUrl: following[index].imageUrl,
followPressed: true,
),
itemCount: following.length,
),
);
}
}
Please specify where dispose method was called for
Unhandled Exception: A Follows was used after being disposed.
E/flutter ( 8465): Once you have called dispose() on a Follows, it can no longer be used.
ChangeNotifierProxyProvider<Auth , Follows>(
create: (ctx) => Follows(),
//update : (context, auth, previous) => Follows()..updates(auth.token, auth.userId)
// You're creating a new Follow object and disposing the old one
update: (context, auth, previous) => previous..updates(auth.token, auth.userId)
),
Instead of creating a new Follows object try to update the previous one, the listen: false will keep the reference of the old object if the ChangeNotifier updates to the new value
Same problem with me.
I Bring "Future.delayed" to apply this resolved below,
Future.delayed
[/] Your MultiProvider Correct.
#override
void didChangeDependencies() {
setState(() {
isLoading = true;
});
Future.delayed(Duration(milliseconds: 300)).then((_) async {
await Provider.of<Follows>(context, listen: false)
.getFollowing(widget.id)
.then((_) {
setState(() {
isLoading = false;
});
});
});
super.didChangeDependencies();
}
Work for me.

Rebuild a FutureBuilder

I am trying to rebuild a FutureBuilder, in my case it is for the purpose of changing the camera that is shown to the user. For that I have to run the Future, the FutureBuilder uses again.
The Future currently looks like this:
body: FutureBuilder(
future: _initializeCameraControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return CameraPreview(_cameraController);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
The Future it is running is this one:
Future<void> _initializeCameraControllerFuture;
#override
void initState() {
super.initState();
if (camerafrontback != true) {
_cameraController =
CameraController(widget.camera[0], ResolutionPreset.veryHigh);
}else{
_cameraController =
CameraController(widget.camera[1], ResolutionPreset.veryHigh);
}
_initializeCameraControllerFuture = _cameraController.initialize();
}
I have a button that should trigger this rebuild of the FutureBuilder, it is also changing the 'camerafrontback' Boolean, so that a different camera is used. It is shown below:
IconButton(
onPressed: () async {
if (camerafrontback == true){
setState(() {
camerafrontback = false;
});
}else{
setState(() {
camerafrontback = true;
});
};
},
At the end, before the last bracket, there must be a statement added that triggers the rebuilds of whole FutureBuilder, but I couldn't find one that suits to my code.
Thanks in advance for your answers!
You need to reinitialize_initializeCameraControllerFuture.
You can do it something like this
#override
void initState() {
super.initState();
_init();
}
...
_init() {
if (camerafrontback) {
_cameraController =
CameraController(widget.camera[1], ResolutionPreset.veryHigh);
} else {
_cameraController =
CameraController(widget.camera[0], ResolutionPreset.veryHigh);
}
_initializeCameraControllerFuture = _cameraController.initialize();
}
...
IconButton(
onPressed: () async {
if (camerafrontback) {
camerafrontback = false;
setState(_init());
} else {
camerafrontback = true;
setState(_init);
}
},
),
to full rebuild your screen you can just replace the screen with the same screen
Navigator.pushReplacement(context,
MaterialPageRoute(
builder: (BuildContext context) =>
*SamePage*()
)
);

Is there any way to listen device location on or off?

I used Geolocator plugin. It's working. but not display a message immediately. the message is displayed like after 2,3 minutes. It does not display real-time.
Geolocator().isLocationServiceEnabled() is future, can't listen right?
FutureBuilder<bool>(
future: Geolocator().isLocationServiceEnabled(),
builder: (context,snapshot){
if(snapshot.hasData){
if(!snapshot.data)
return CustomText(
text: 'GPS Interrupted',
);
else
return Container();
} else{
return Container();
}
}
)
I used this widget like this,
bottom: PreferredSize(child: FutureBuilder<bool>(
I found this way, It's working.
#override
void initState() {
super.initState();
const Duration checkingTime = Duration(seconds:5);
_timer = Timer.periodic(checkingTime, (Timer t) => checkLocation());//Using GeoLocator
}
#override
void dispose() {
super.dispose();
if( _timer != null) _timer.cancel();
}
void checkLocation(){
Geolocator().isLocationServiceEnabled().then(locationService);
}
void locationService(bool result){
if(!mounted) return;
setState(() {
if(result)
isLocationEnable = true;
else
isLocationEnable = false;
});
}