In Flutter, I don't get any callback when the application is killed. Now, how can I stop streaming when my application is killed?
You should use the Stateful Widget and there is a dispose method, there you can dispose everything you want when application is killed.
Example:
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
}
#override
void dispose() {
//something.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container());
}
}
You must use app lifecycle state in Flutter.
Related
For the code below, on the press of the icon of the first class, I want to send data to the second class. First-class just contains the data that needs to pass to the second class. There is no way or not allowed to navigate from first to second class. The only option to navigate to the second class is from the third class. I tried creating a constructor in the second class and implemented
second page(data:_getData.text). But there is no way i am getting the value. I am just getting null.
**First class**
onPressed: () { setState(() => _getData.text);
**SecondPage(data:_getData.text);**
}
**Second class**
class SecondPage extends StatefulWidget {
String? data;
SecondPage({this.data});
#override
_SecondPageState createState() => _SecondPageState(data);
}
class _SecondPageState extends State<SecondPage> {
String? data;
_SecondPageState(this.data);
**Third class**
Get.to(SecondPage)
if you change a lot of states, you would use bloc or any state management. because it is good for the app. if you want only this thing, you use the below code.
First Screen
class FirstScreen extends StatefulWidget {
const FirstScreen({Key? key}) : super(key: key);
#override
State<FirstScreen> createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
String title = "no value_f";
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
title = "value";
});
},
child: Text("Press")),
SecondScreen(title: title),
],
),
);
}
}
Second Screen
class SecondScreen extends StatefulWidget {
String title;
SecondScreen({Key? key, required this.title}) : super(key: key);
#override
State<SecondScreen> createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
#override
void initState() {
widget.title = "no value";
super.initState();
}
#override
Widget build(BuildContext context) {
return Text(widget.title);
}
}
I want to create a responsive appbar without need to setState to the entire scaffold when there are changes. The problem is I can set a BottomNavigationBar widget to the scaffold's bottomNavigationBar but I can't do the same with an AppBar to set to it's appBar. I get this error
The argument type 'TopBar' can't be assigned to the parameter type 'PreferredSizeWidget'
I've simplified the code with the States only part.
class StateLayoutNav extends State<LayoutNav>{
#override
Widget build(BuildContext context) => Scaffold(
bottomNavigationBar : BottomBar(), appBar : TopBar()
);
}
class StateTopBar extends State<TopBar>{
#override
Widget build(BuildContext context) => AppBar();
}
class StateBottomBar extends State<BottomBar>{
#override
Widget build(BuildContext context) => BottomNavigationBar();
}
My solution would be implementing your Appbar widget with PreferredSizeWidget as Appbar need to be of preferredSize
class TopBar extends StatefulWidget with PreferredSizeWidget {
TopBar({Key key}) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key);
#override
final Size preferredSize;
#override
StateTopBar createState() => StateTopBar();
}
class StateTopBar extends State<TopBar>{
#override
Widget build(BuildContext context) => AppBar();
}
Try appBar: TopBar() as PreferredSizeWidget
Try this. It will give you a custom app bar with any customisable widget. You can add fixed Container. Solution is implementing app bar with PreferredSizeWidget.
class TopBar extends StatefulWidget implements PreferredSizeWidget {
TopBar({Key? key}) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key);
#override
final Size preferredSize; // default is 56.0
#override
_TopBarState createState() => _TopBarState();
}
class _TopBarState extends State<TopBar>{
#override
Widget build(BuildContext context) {
return Container( child: Text("Sample App Bar") );
}
}
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
OrientationSingleton.left = true;
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft])
.then((_) {
runApp(new MyApp());
});
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
Here's my app. I've found some tutorials on how to remove it: flutter remove back button on appbar but it's for an AppBar. I tried making my app work on an AppBar but I get
MediaQuery.of() called with a context that does not contain a MediaQuery.
Because I rely on MediaQuery.of() inside my app.
So, how do I remove the Android back, home and square buttons on Flutter for a MaterialApp?
As stated in the error message, SystemChrome requires context - a place to call it could be the initState() method of the Widget:
class MyApp extends StatefulWidget {
const MyApp({ Key key }) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
OrientationSingleton.left = true;
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
}
#override
Widget build(BuildContext context) {
return MaterialApp(); // your MaterialApp class
}
}
To hide the system bottom bar on Android, one option could be to call the setEnabledSystemUIOverlays() function with an empty list:
SystemChrome.setEnabledSystemUIOverlays([]);
However, this function is not globally supported on all Android devices.
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();
}
}
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);
});
});
}