I call method in ScopedModel from outside ScopedModel (on button press). But PlatformException is not catch as I expect.
PlatformException is only catch in ScopedModel Method try/catch. It is not catch in button press try/catch.
Button press:
child: RaisedButton(
onPressed: () async {
try {
await loginModel.signInWithGoogle();
} on PlatformException catch (e) {
debugPrint(e.toString());
}
},
ScopedModel Method:
await _signInWithGoogle();
…
Future<void> _signInWithGoogle() async {
…
throw PlatformException(code: ‘Test Exception’);
} on PlatformException catch (e) {
debugPrint(e.toString());
}
I throw PlatformException in ScopedModel to test when exception is throw from this method.
Why there is difference? I want catch PlatformException in button press
Thanks for help!
It should work. See a very simple example:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
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();
}
class _MyHomePageState extends State<MyHomePage> {
Login userLogin = Login();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Simple exception test',
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
try {
await userLogin.signInWithGoogle();
} on PlatformException catch (e) {
print('Error ...:');
print(e);
}
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class Login {
Future<void> signInWithGoogle() async {
throw PlatformException(code: 'Test Exception');
}
}
Related
I am new to flutter and I am trying to call api data in listview builder inside future builder. But I am getting null data in snapshot.
My code is below:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
String token;
SharedPreferences sharedPreferences;
class ContinueW extends StatefulWidget {
#override
_ContinueWState createState() => _ContinueWState();
}
class _ContinueWState extends State<ContinueW> {
Future getTokenValue() async {
SharedPreferences espf = await SharedPreferences.getInstance();
token = espf.getString('tokenvalue');
return token;
}
Future createUser() async {
String url ='http://3.137.182.252:8000/continue-watching';
print('token');
Map<String, String> headers = {
'token': token,
};
await http.get(url, headers: headers).then((response){
print('Entered');
//print(response.body);
var jre= jsonDecode(response.body);
return jre;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder(
future: getTokenValue(),
builder: (BuildContext context,snapshot){
if(snapshot.hasData){
return cbuild();
} else{
return CircularProgressIndicator();
}
},
),
),
);
}
Widget cbuild(){
return new FutureBuilder(
future: createUser(),
builder: (BuildContext context,snapshot) {
if(snapshot.hasData) {
return ListView.builder(
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
backgroundImage: snapshot.data['thumburl'] != null
? NetworkImage(snapshot.data['thumburl'])
: Container(),),
title: Text(snapshot.data[index]['name']),
subtitle: Text(snapshot.data[index]['description']),
);
},
);
}
else{
return CircularProgressIndicator();
}
}
);
}
}
ListTile(
leading: CircleAvatar(
backgroundImage: snapshot.data[index]['thumburl'] != null
? NetworkImage(snapshot.data[index]['thumburl'])
: Container(),),
title: Text(snapshot.data[index]['name']),
subtitle: Text(snapshot.data[index]['description']),
);
as according to details provided by you. you may be missing [index]with ['thumburl'],
if it's still not working then you need to provide JSON formated data
I have a simple app with two dart files: main.dart and bukalapak.dart
For demonstration purposes the app only has two Future Text() widgets. Basically one Text widget gets the name of a certain html, the other widget gets the total of the same html. Don't ask why but the future builder for "name" has to be in a separate stateful widget in bukalapak.dart. My question is how can I wait until the html is not null then display the total Text widget, because I can easily just call the url again but that would be doing twice the work. I only want to have to call the http.get once.
Here is the code for main.dart:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
Bukalapak bukalapak = Bukalapak();
return Scaffold(
appBar: AppBar(
title: Text('data'),
),
body: Container(
child: Column(
children: <Widget>[
RandomWidget(
bukalapak: bukalapak,
),
FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Total results: ${snapshot.data}')),
);
},
future: bukalapak.getTotal(),
)
],
),
),
);
}
}
The code for bukalapak.dart:
class Bukalapak {
var html;
Future<dynamic> getTotal() async {
// wait until html != null, then perform this
var a = html.querySelectorAll(
'#display_product_search > div.product-pagination-wrapper > div.pagination > span.last-page');
dynamic total = int.parse(a[0].text) * 50;
total = '$total'.replaceAllMapped(
new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
return total;
}
Future<dynamic> getName() async {
http.Response response = await http.get(
'https://www.bukalapak.com/products/s?from=omnisearch&from_keyword_history=false&page=0&search%5Bkeywords%5D=paper&search_source=omnisearch_organic&source=navbar&utf8=✓');
if (response.statusCode == 200) {
String data = response.body;
html = parse(data);
var nameElement = html.querySelector(
'li.col-12--2 > div.product-card > article > div.product-media > a');
String title = nameElement.attributes['title'];
return title;
} else {
throw Exception('Bukalapak error: statusCode= ${response.statusCode}');
}
}
}
class RandomWidget extends StatefulWidget {
RandomWidget({this.bukalapak});
final Bukalapak bukalapak;
#override
_TextState createState() => _TextState();
}
class _TextState extends State<RandomWidget> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Name results: ${snapshot.data}')),
);
},
future: widget.bukalapak.getName(),
);
}
}
you can pass any function which notify parent widget to build future.
Following code will help you more:
class DeleteWidget extends StatefulWidget {
#override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
Bukalapak bukalapak = Bukalapak();
Widget first;
bool isBuild = false;
nowbuildtotal() async {
await Future.delayed(Duration(microseconds: 1));
setState(() {
isBuild = true;
});
}
#override
void initState() {
super.initState();
first = RandomWidget(
bukalapak: bukalapak,
buildnow: nowbuildtotal,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('data'),
),
body: Container(
child: Column(
children: <Widget>[
first,
isBuild
? FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Total results: ${snapshot.data}')),
);
},
future: bukalapak.getTotal(),
)
: Container()
],
),
),
);
}
}
class RandomWidget extends StatefulWidget {
RandomWidget({this.bukalapak, this.buildnow});
final Bukalapak bukalapak;
final Function buildnow;
#override
_TextState createState() => _TextState();
}
class _TextState extends State<RandomWidget> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
widget.buildnow();
}
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Name results: ${snapshot.data}')),
);
},
future: widget.bukalapak.getName(),
);
}
}
class Bukalapak {
var html;
Future<dynamic> getTotal() async {
// wait until html != null, then perform this
var a = await html.querySelectorAll(
'#display_product_search > div.product-pagination-wrapper > div.pagination > span.last-page');
dynamic total = int.parse(a[0].text) * 50;
total = '$total'.replaceAllMapped(
new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
return total;
}
Future<dynamic> getName() async {
print("object");
http.Response response = await http.get(
'https://www.bukalapak.com/products/s?from=omnisearch&from_keyword_history=false&page=0&search%5Bkeywords%5D=paper&search_source=omnisearch_organic&source=navbar&utf8=✓');
if (response.statusCode == 200) {
String data = response.body;
html = parse(data);
var nameElement = html.querySelector(
'li.col-12--2 > div.product-card > article > div.product-media > a');
String title = nameElement.attributes['title'];
return title;
} else {
throw Exception('Bukalapak error: statusCode= ${response.statusCode}');
}
}
}
how to show video in flutter?
i should recieve an api have url of video to show, but it sitll white page with my progress indicator,
I was trying for a week but couldn't do any thing,
then I tried to use assets video but it didn't work too
here is my code so what is wrong?
please help me, thank you.
class _MyHomePageState extends State<MyHomePage> {
VideoPlayerController _videoPlayerController;
Future<void> _initializedVideoPlayerFuture;
String videoUrl =
'https://storage.koolshy.co/shasha-transcoded-videos-2019/1c18ada9-a82a-4490-ad2f-87c3ba3ed251_240.mp4';
String videoTrack = 'assets/video.mp4';
#override
void initState() {
super.initState();
// _videoPlayerController = VideoPlayerController.network(videoUrl);
_videoPlayerController = VideoPlayerController.asset(videoTrack);
_videoPlayerController.setLooping(true);
_videoPlayerController.setVolume(1.0);
}
#override
void dispose() {
super.dispose();
_videoPlayerController.dispose();
}
void _incrementCounter() {
setState(() {
_videoPlayerController.value.isPlaying
? _videoPlayerController.pause()
: _videoPlayerController.play();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FutureBuilder(
future: _initializedVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'play/pause',
child: Icon(_videoPlayerController.value.isPlaying
? Icons.pause
: Icons.play_arrow),
),
);
}
}
there is a missing statement
_initializedVideoPlayerFuture = _videoPlayerController.initialize();
should be in the initstate()
void initState() {
super.initState();
_videoPlayerController = VideoPlayerController.network(videoUrl);
// _videoPlayerController = VideoPlayerController.asset(videoTrack);
_initializedVideoPlayerFuture = _videoPlayerController.initialize();
_videoPlayerController.setLooping(true);
_videoPlayerController.setVolume(1.0);
}
I'm new to flutter and I know it's a very basic question but I've been stuck on this one for three days. I just want to fetch data from an API on object creation. When you run the code it throws an exception But when you Hot Reload it, the async operation starts to work fine. Kindly tell me where I'm wrong. I myself have made extra classes although one should avoid to code with that approach.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main(){
runApp(
MaterialApp(
title : "Quake",
home : HomePage()
)
);
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
dataRepository.init();
}
#override
Widget build(BuildContext context) {
return Reading();
}
}
class Reading extends StatefulWidget {
#override
_ReadingState createState() => _ReadingState();
}
class _ReadingState extends State<Reading> {
Map _data = Map();
List _features = List();
#override
void initState() {
super.initState();
_data = dataRepository.getReading();
_features = _data['features'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Quake"),
centerTitle: true,
backgroundColor: Colors.black,
),
body : Center(
child : ListView.builder(
itemCount: _features.length,
padding: const EdgeInsets.all(14.5),
itemBuilder: (BuildContext context, int position){
var format = DateFormat.yMMMd("en_US").add_jm();
var _date = format.format( DateTime.fromMicrosecondsSinceEpoch(_features[position]['properties']['time']*1000, isUtc: true));
return Column(
children: <Widget>[
Divider(height : 5.5),
ListTile(
title: Text("$_date",
style: TextStyle(fontSize: 16.0)),
subtitle: Text("${_features[position]['properties']['place']}",
style: TextStyle(fontSize: 13.0)),
leading: CircleAvatar(
backgroundColor : Colors.black,
child : Text("${_features[position]['properties']['mag']}", style: TextStyle( color: Colors.white))
),
onTap: () => _windowOnTapping(context, _features[position]['properties']['title']),
)],);},)));}}
Future _windowOnTapping(BuildContext context, String message){
var alert = AlertDialog(
title: Text("Quakes"),
content: Text(message),
actions: <Widget>[
FlatButton ( child: Text("OK"), onPressed: (){ Navigator.pop(context);})
],
);
showDialog( context: context, builder: (context)=> alert);
}
final DataRepository dataRepository = DataRepository._private();
class DataRepository{
DataRepository._private();
Map _data;
void init() async{
String apiUrl = 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson';
http.Response response = await http.get(apiUrl);
_data = json.decode(response.body);
}
Map getReading(){
return _data;
}
}
Use a FutureBuilder to read the Future and only render the component after it returns, something like this:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(MaterialApp(title: "Quake", home: HomePage()));
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Reading();
}
}
class Reading extends StatefulWidget {
#override
_ReadingState createState() => _ReadingState();
}
class _ReadingState extends State<Reading> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Quake"),
centerTitle: true,
backgroundColor: Colors.black,
),
body: FutureBuilder<Map>(
future: dataRepository.getReading(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var features = snapshot.data['features'];
return Center(
child: ListView.builder(
itemCount: features.length,
padding: const EdgeInsets.all(14.5),
itemBuilder: (BuildContext context, int position) {
var format = DateFormat.yMMMd("en_US").add_jm();
var _date = format.format(
DateTime.fromMicrosecondsSinceEpoch(
features[position]['properties']['time'] * 1000,
isUtc: true));
return Column(
children: <Widget>[
Divider(height: 5.5),
ListTile(
title:
Text("$_date", style: TextStyle(fontSize: 16.0)),
subtitle: Text(
"${features[position]['properties']['place']}",
style: TextStyle(fontSize: 13.0)),
leading: CircleAvatar(
backgroundColor: Colors.black,
child: Text(
"${features[position]['properties']['mag']}",
style: TextStyle(color: Colors.white))),
onTap: () => _windowOnTapping(context,
features[position]['properties']['title']),
)
],
);
},
));
} else {
return Text("Loading");
}
}));
}
}
Future _windowOnTapping(BuildContext context, String message) {
var alert = AlertDialog(
title: Text("Quakes"),
content: Text(message),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.pop(context);
})
],
);
showDialog(context: context, builder: (context) => alert);
}
final DataRepository dataRepository = DataRepository._private();
class DataRepository {
DataRepository._private();
Future<Map> getReading() async {
String apiUrl =
'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson';
http.Response response = await http.get(apiUrl);
var data = json.decode(response.body);
print(data);
return data;
}
}
I tried to Save and share a variable Phone number string from a tabbar page to homepage. Currently my variable is display only after reload. I tried to display variable just after saved it.
my code :
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _variable;
#override
void initState() {
super.initState();
_loadvariable();
}
_loadvariable() async { // load variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_variable = (prefs.getString('variable'));
}
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
bottomNavigationBar: BottomAppBar(
color: Colors.blue,
elevation: 20.0,
child: ButtonBar(
alignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(Icons.phone),
color: Colors.white,
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new Phone_Page()),
);
},
),
],
),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'$_variable',
style: Theme.of(context).textTheme.display1,
),
],
),
),
);
}
}
here is my seconde page class, I can clic on the phone icon to show a dialog box, and I can write on the text field. After clic on save button my textfield is save, the dialog box is close and my variable is display on the card. But after return on the Homepage my variable isn't display. I need to reload the app to display it :(
class Phone_Page extends StatefulWidget {
#override
Phone_PageState createState() => Phone_PageState();
}
class Phone_PageState extends State<Phone_Page> {
final TextEditingController controller = new TextEditingController();
String _variable;
_loadvariable() async { // load variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_variable = (prefs.getString('variable'))?? "";
});
}
_savevariable() async { // save variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.setString('variable', controller.text);
});
}
_deletevariable() async { //delete variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.remove('variable');
});
}
#override
void initState() {
super.initState();
_loadvariable()?? "";
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Phone"),
),
body: new Center(
child: new ListView(
children: <Widget>[
new Card(
child: new Container(
padding: const EdgeInsets.all(20.0),
child: new Row(
children: [
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new Text(
'$_variable',
style: new TextStyle(
color: Colors.grey[500],
),
),
],
),
),
new IconButton(
icon: new Icon(Icons.add_call),
onPressed: ()
{
_showDialog();
}
),
new IconButton(
icon: new Icon(Icons.delete),
onPressed: () { setState(() {
_deletevariable();
_savevariable();
_loadvariable();
}
);
},
),
],
),
),
),
]
)
)
);
}
_showDialog() async {
await showDialog<String>(
context: context,
child: new AlertDialog(
// contentPadding: const EdgeInsets.all(16.0),
content: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
controller: controller,
autofocus: true,
decoration: new InputDecoration(
labelText: 'number', hintText: '06 - - - - - - - -'),
// keyboardType: TextInputType.number,
),
)
],
),
actions: <Widget>[
new FlatButton(
child: const Text('save'),
onPressed: (){
setState(() { {
_savevariable();
Navigator.pop(context);
}
}
);
}
)
],
),
);
}
}
To achieve what you want, you need to call _loadvariable() function of class MyHomePage from PhonePage class. To do that:
Refactor and remove _ from _loadvariable() and _MyHomePageState so that it won't be private anymore.
Pass MyHomePageState class instance to PhonePage as follows:
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new PhonePage(
myHomePageState: this,
)),
);
Call loadvariable() in _savevariable() like
_savevariable() async {
// save variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.setString('variable', controller.text);
});
widget.myHomePageState.loadvariable();
}
Make sure the myHomePageState type is var so that you won't get type error:
class PhonePage extends StatefulWidget {
var myHomePageState;
PhonePage({this.myHomePageState});
#override
PhonPageState createState() => PhonPageState();
}