Flutter: Why Future.then() doesn't work on class variable? - android

Code I show you is the simplified code which I'm troubled in.
My expected result is [1,2,3,4,5,6], but app says [1,2,3].
I know "loadMoreInterger()" should be in "initState()", but for some reason I have to put it in Widget build() {"HERE"}.
I wonder if why doesn't it work, and the solution for correct result.....
I really appreciate for your help :)
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
// ↓↓↓↓↓↓↓↓↓↓↓WHERE I CANNOT UNDERSTAND↓↓↓↓↓↓↓↓↓↓↓
class _MyHomePageState extends State<MyHomePage> {
List<int> intList = [1,2,3];
Future<List<int>> loadMoreInteger() async {
print('Future');
return [4,5,6];
}
#override
Widget build(BuildContext context) {
loadMoreInteger().then((value) {
intList.addAll(value); // why doesn't it work?
});
print("console: $intList");
return Scaffold(
body: Center(
child: Text("display: $intList")
)
);
}
}
//Expected result: [1,2,3,4,5,6]
//Actual result: [1,2,3]

put it in initState override function and it works for yu !!!!
List<int> intList = new List();
Future<List<int>> loadMoreInteger() async {
print('Future');
return [4,5,6];
}
#override
void initState() {
super.initState();
intList = [1,2,3];
loadMoreInteger().then((v){
setState(() {
intList.addAll(v) ;
});
}); }

Here is what your build method does: after entering the method it starts to execute loadMoreInteger() future. Afterwards even if executed future is synchronous it only schedules call of next future that is produced by calling .then. So build method continues to execute with old intList value. And [4,5,6] will be added only after build completes.
In general you can wait for future to complete by calling it with await keyword. But build method is overriden and already has predefined return type that is not future, so you can not call await inside build.
What you can do:
I highly recommend moving any manipulation with data from build method. Its purpose is to produce widgets as fast as possible. It can be called multiple times at some moment unexpected for developer.
One of possible options for you will be moving loadMoreInteger() to initState and calling setState when intList is updated
#override
void initState() {
super.initState();
loadMoreInteger().then((value) {
setState(() {
intList.addAll(value);
});
});
}

Related

My flutter property has not assign value in future block

My flutter property has not changed in future blocks. I tried setState(() {}) but not working.
I uninstalled flutterSdk and android SDK then I installed this SDK but still has not changed.
I had the same situation in my previous project. I copied the code of other pages and pasted it to the page that is not working. The page is working a little then page is wrong
this is my code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class apiPage extends StatefulWidget {
const apiPage({Key? key}) : super(key: key);
#override
State<apiPage> createState() => _apiPageState();
}
class _apiPageState extends State<apiPage> {
String _response="exe";//this property is not working
Future <void> ApiCall() async{
String adres="www.api";
http.Response cevap=await http.get(Uri.parse(adres));
if(cevap.statusCode==200){
_response=cevap.body;//property needs to be changed
}else{
_response="error";//feature needs to be changed
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Text('$_response'),
]
),
);
}
}
When you like to update UI with new value, call setState on widget-state class. Here you can do,
if(cevap.statusCode==200){
setState((){
_response=cevap.body;
});
}else{
setState((){
_response="error";
});
}
Make sure to call the ApiCall() method.
A better choice will be using FutureBuilder for future method. Find more about FutureBuilder and StatefulWidget.

Android Alarm Manager Plus in Flutter never fires oneShot

I am trying to get a handle on the nearly entirely undocumented Android Alarm Manager Plus, and have a very simple app to press a button, set an alarm, and fire the alarm as follows:
import 'package:flutter/material.dart';
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await AndroidAlarmManager.initialize();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.pink,
),
home: SetAlarmPage(),
);
}
}
class SetAlarmPage extends StatefulWidget {
const SetAlarmPage({Key? key}) : super(key: key);
#override
State<SetAlarmPage> createState() => _SetAlarmPageState();
}
class _SetAlarmPageState extends State<SetAlarmPage> {
String test = "Press Me!";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Set an Alarm")),
body: Center(
child: ElevatedButton(
child: Text(test),
onPressed: () {
print(test + " Button Pressed...");
setAlarm();
},
),
),
floatingActionButton:
FloatingActionButton(onPressed: null, child: Icon(Icons.add)),
);
}
void setAlarm() async {
print("setAlarm");
final int alarmID = 1;
await AndroidAlarmManager.oneShot(Duration(minutes: 1), alarmID, playAlarm);
}
void playAlarm() {
print("playAlarm");
setState(() {
test = "Pressed!";
});
}
}
I manage to get the alarm service started, but beyond that, nothing. I have tried initializing the AndroidAlarmManager object both in main and in setAlarm, tried moving around ensureInitialized, tried setting different durations in oneShot, tried changing the ID, and tried firing a more simple alarm function. No matter what I do, the alarm wont set or fire.
I'm pretty sure its something simple, but for a core function of android, there is no real documentation on how to use it to speak of.
Does anyone know what android alarm manager plus wants that I'm not providing, here?
first did you add the required AndroidManifest.xml tags?
second thing, by reading the documentation on https://pub.dev/packages/android_alarm_manager_plus, the callback is executed on a separate Isolate thus you can't pass a function from an instance class since isolates don't share memory (isolate is to run a piece of code on another thread).
You can make sure that the plugin is working by adding a static function with a print statement (you can't call setState from a static function)
change the playAlarm function into:
static void playAlarm() {
print("playAlarm");
}
this function is used to verify that the plugin is working

ERROR || FLUTTER || 'owner!._debugCurrentBuildTarget == this': is not true

I am new to Android Development. I created a flutter project and just returned a Text Widget using a stateless class but I am getting this error. I tried reading about it on the blogs regarding this error. I think its related to calling an instance of a stateless widget in the same class itself but I am not sure.
stack overflow post
Here's my code:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Text('Hello'),
);
}
}
Getting this O/P:
What to do ?
You must use MaterialApp Widget in the beginning. If you do this, the problem will be solved. But I recommend you to wrap the Text Widget with Scaffold too.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Text('Hello'),
);
}
}

Platform location permission error with Flutter isolates

I'm attempting to run location updates on a Flutter isolate thread, the error is only present when running an isolate. Location requests works without issues on the main thread. The goal here is to run this as a background service, working with dart code only.
I am using Geolocator plugin for location requests.
This is the error I am facing when starting the isolate:
Exception has occurred. FlutterError
(ServicesBinding.defaultBinaryMessenger was accessed before the
binding was initialized.
I have tried to include the WidgetsFlutterBinding.ensureInitialized() before runApp but without results.
Looking at the call stack of the error, it seems problems occur at the android location platform call: checkPermissionStatus
This happens regardless of what location plugin I am using, it stops at the permission status check.
I have figured it could have something to do with awaiting location permission user input, but this check will fail on a non-ui thread?
See this simple main.dart file for an example:
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Isolate location test',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Isolate location test'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Isolate isolate;
bool isRunning = false;
String output = '';
ReceivePort receivePort;
void start() async {
receivePort = ReceivePort();
await Isolate.spawn(locationUpdate, receivePort.sendPort);
receivePort.listen((dynamic data) {
setState(() {
isRunning = true;
});
}, onDone: () {
print("done");
});
}
void stop() {
if (isolate != null) {
setState(() {
isRunning = false;
});
receivePort.close();
isolate.kill(priority: Isolate.immediate);
isolate = null;
}
}
static void locationUpdate(SendPort sendPort) async {
Geolocator().checkGeolocationPermissionStatus().then((status) {
sendPort.send(status);
});
// Geolocator().getCurrentPosition().then((pos) {
// sendPort.send(pos);
// });
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(child: Text(output)),
floatingActionButton: FloatingActionButton(
onPressed: isRunning ? stop : start,
child: Icon(isRunning ? Icons.stop : Icons.play_circle_filled),
),
);
}
}

AdMob not initialized from flutter notification

So I have a very simple application.
In Main I initialize Admob and call Root Widget.
From Root I show a Stateful Widget "Home".
From Home Call the Notification Logic.
When you "click" on the notification I send you again to Root.
When I first run the application, the adMobBanner works good.
After you receive the notification and you click on it, the app starts again, everything works as expected but the adMobBanner is a black banner now.
I think the Admob is not initialized properly. I tried to "Admob.initialize("appId")" in Root, in LocalNotification widget, everywhere, but still the same result.
Any ideas?
void main() async {
Admob.initialize("appId");
runApp(Root());
}
class Root extends StatelessWidget {
final String title = "Title";
Root();
#override
Widget build(BuildContext context) {
return MaterialApp(
title: title,
),
home: Home(title: title));
}
}
class Home extends StatefulWidget {
final String title;
Home({this.title});
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
final adMobBanner = AdmobBanner(adUnitId: "id", adSize: AdmobBannerSize.BANNER);
return Scaffold(
appBar: appBar,
body: Column(
children: <Widget>[
Container(),
adMobBanner,
LocalNotification()
],
),
);
}
}
class LocalNotification extends StatefulWidget {
#override
_LocalNotificationState createState() => _LocalNotificationState();
}
class _LocalNotificationState extends State<LocalNotification> {
void initState() {
super.initState();
//initialization notification plugin
showNotification(); //the notification with onSelectNotification callback
}
Future onSelectNotification(String payload) async {
await Navigator.push(context, MaterialPageRoute(builder: (context) {
return Root(); // send you to Root again
}));
}
#override
Widget build(BuildContext context) {
return Container();
}
}

Categories

Resources