GoogleMap's onCameraIdle stops firing when in a SingleChildScrollView - google-maps

I have a design where a SingleChildScrollView has a GoogleMap on the first 50% on the screen, and a listing of items in the lower 50%. The user can scroll the entire view up to look at all of the listings. However, at times the Map stops firing the onCameraIdle if the users scrolls the page, and it just won't start firing it again.
onCameraMove and onTap works just fine. It is just onCameraIdle that won't fire.
SingleChildScrollView(
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: screenSize.height / 2,
child: GoogleMap(
key: Key("GMap"),
mapType: MapType.normal,
markers: Set<Marker>.of(markers.values),
gestureRecognizers: Set()
..add(Factory<PanGestureRecognizer>(
() => PanGestureRecognizer()))
..add(
Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer()),
)
..add(
Factory<HorizontalDragGestureRecognizer>(
() => HorizontalDragGestureRecognizer()),
)
..add(
Factory<ScaleGestureRecognizer>(
() => ScaleGestureRecognizer()),
),
initialCameraPosition: CameraPosition(
target: LatLng(14.551620, 121.053329), zoom: 14.5),
onMapCreated: (GoogleMapController controller) {
if (!_controller.isCompleted) {
_controller.complete(controller);
_lastCameraPosition = CameraPosition(
target: LatLng(14.551620, 121.053329), zoom: 14.5);
}
},
myLocationEnabled: true,
myLocationButtonEnabled: true,
onCameraIdle: () {
print("547: onCameraIdle");
_fetchOffers();
},
onCameraMove: (value) {
print("552: onCameraMove");
_lastCameraPosition = value;
},
onTap: (value) {
// Load items for current view if deselecting a marker
print('556: Tapped outside');
},
),
),
Positioned(
top: 50,
right: 20,
child: Container(
height: 30,
decoration: BoxDecoration(
border: Border.all(
color: _userBalance > 0
? globals.themeColor4
: globals.themeColor2,
width: 2),
boxShadow: [
BoxShadow(
blurRadius: 10.0,
color: Colors.black.withOpacity(.5),
offset: Offset(3.0, 4.0),
),
],
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(10.0))),
child: Center(
child: Padding(
padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
child: Text(
"Balance: \u{20B1} ${_userBalance.toStringAsFixed(0)}",
style: TextStyle(
color: Colors.black,
fontSize: 14,
),
),
),
),
),
),
],
),
AnimatedContainer(
color: Colors.white,
// Use the properties stored in the State class.
width: double.infinity,
height: _loaderHeight,
// Define how long the animation should take.
duration: Duration(seconds: 1),
// Provide an optional curve to make the animation feel smoother.
curve: Curves.fastOutSlowIn,
child: Center(
child: Text(
"Loading, please wait",
style: TextStyle(color: Colors.grey),
),
),
),
Container(
color: Colors.white,
child: _offers == null
? Container(
child: Padding(
padding: EdgeInsets.all(30),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(MdiIcons.foodAppleOutline,
size: 60, color: globals.themeColor4),
Padding(padding: EdgeInsets.only(right: 20)),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Fetching offers",
style: TextStyle(
color: globals.themeColor4,
fontWeight: FontWeight.bold)),
Padding(padding: EdgeInsets.only(top: 5)),
Text(
"We are fetching offers for you, please hold on...",
style: TextStyle(color: Colors.grey)),
],
),
),
],
),
),
)
: Column(children: _offers),
),
],
),
),
Has anyone encountered this before and have a solution to it?

I replicated a simple version of your sample, but I wasn’t able to reproduce an issue with onCameraIdle not firing.
Now, based off of my sample, there were some behaviors that you could have misinterpreted as not working, but is actually the scrollview’s behavior taking over (since this is all inside a scrollview):
Sometimes a downward gesture on the map would pull on the scrollview instead of the map.
And an upward gesture would scroll the scrollview instead of interacting with the map.
But without any further details into the rest of your code, or a mcve that can easily reproduce your issue, it’s hard to say what’s really going on.
However, as Patrick Kelly mentioned, it’s also possible that the lack of a KeepAlive might have eventually led to the temporary disposing of your maps widget. Which is why ListView was suggested because this feature is built into it.
On the other hand, you can also implement AutomaticKeepAliveClientMixin for a similar effect, as seen over at https://stackoverflow.com/a/51738269/6668797 (but beware of the warning for the widget disposing).
Anyways, here’s my sample, and I had to make an educated guess on what your _fetchOffers() is:
class _MyHomePageState extends State<MyHomePage> {
// testing
int fetchCount = 0;
List<Widget> _offers;
_fetchOffers() {
fetchCount++;
// simulate varying data
var rng = new Random();
int start = rng.nextInt(10);
int end = start + 3 + rng.nextInt(30);
// build sample list
List<Widget> list = new List();
for (int i = start; i < end; i++) {
list.add(Text('offer$i', style: new TextStyle(fontSize: 30.0)));
}
// assuming you are using setState()
setState(() {
_offers = list;
});
}
// from google maps sample
Completer<GoogleMapController> _controller = Completer();
static final CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746,
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 2,
child: GoogleMap(
mapType: MapType.normal,
initialCameraPosition: _kGooglePlex,
gestureRecognizers: Set()
..add(Factory<PanGestureRecognizer>(() => PanGestureRecognizer()))
..add(Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer()))
..add(Factory<HorizontalDragGestureRecognizer>(() => HorizontalDragGestureRecognizer()))
..add(Factory<ScaleGestureRecognizer>(() => ScaleGestureRecognizer())),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
onCameraIdle: () {
_fetchOffers();
},
),
),
]
),
Container(
child: _offers == null
? Container(child: Text("Fetching offers"))
: Column(children: _offers)
),
],
),
),
floatingActionButton: FloatingActionButton(
// for logging _fetchOffers activity
child: Text(fetchCount.toString())
),
);
}
}
onCameraIdle fired every time for me, and I could visually confirm it with the changing offers data as well as the fetchCount log.

You could use a ListView or a CustomScrollView with KeepAlive
This prevents Widgets from being thrown out when scrolled out of view.
I would alternatively recommend digging into the ScrollController class

Related

Call function in onTap method directly or using fat operator in Dart/Flutter?

I have created a function in my app which makes a custom widget according to my need. Here is the code for the function
Widget customCircularButton(
{String title, String subTitle, String img, void Function() onTap}) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: onTap,
child: CircleAvatar(
radius: screenWidth(context) / 6,
backgroundColor: pColor,
child: CircleAvatar(
radius: screenWidth(context) / 6 - 2,
backgroundColor: Colors.white,
backgroundImage: Image.asset(img).image,
),
),
),
Container(
margin: EdgeInsets.all(5),
child: Text(
title,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
),
Container(
margin: EdgeInsets.all(5),
width: screenWidth(context) / 3,
child: Text(
subTitle,
style: TextStyle(fontWeight: FontWeight.w300, fontSize: 12),
textAlign: TextAlign.center,
))
],
);
}
So to call this function into my widget i call it like this
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
customCircularButton(
title: 'Donate',
subTitle: 'Donate/Buy food for needy',
img: 'assets/images/donate-food.png',
onTap: donateDiaolg,
),
customCircularButton(
title: 'Become Volunteer',
subTitle: 'Distribute food to the needy',
img: 'assets/images/become-volunteer.png',
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BecomeVolunteer()));
}),
],
),
Here donateDialog is another function which opens up a dialog.
void donateDiaolg() {
showDialog(..implementation..);}
So my doubt here is that should is use fat operator to call the donateDialog function or just call it like there in above code.
My basic question is should i use this
onTap: () => donateDialog(),
or this
onTap: donateDialog(),
or is it okay to do like this
onTap: donateDialog
It would be better if someone explains me these three function call.
It depends on function signature. for example onTap property needs function with no argument. if your custom function is same you can use your function name directly like onTap: myFunc. if your function's signature take 1 or more arguments you should pass empty function to onTap and call your function through it.

Flutter how to in a expanded list view

Hello good day everyone i want to make my listview into a expanded listview i pull my data using mysql
i want to display first the transaction id and the vesselname then in the side it has it mut have a arrow that when you click it it will show other information details.
Widget build(BuildContext context) {
return Scaffold(
body: RefreshIndicator(
onRefresh: getData,
key: _refresh,
child: loading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: list.length,
itemBuilder: (context, i) {
final x = list[i];
debugPrint(x.toString());
return Container(
padding: EdgeInsets.all(20.0),
child: Row(
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
the data will be shown first is transaction id and vessel name a arrow icon on the side when it is click it will show the other information
Text(
'Transaction ID:\t' + x.transaction_id,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
),
Text('Vessel Name:\t' + x.vesselname,
style: TextStyle(fontSize: 20.0)),
//this will be the the information displayed after the side arrow will be click
Text('Type of Port :\t' + x.typeofport.capitalize(),
style: TextStyle(fontSize: 20.0)),
Text('Vessel Number:\t' + x.voyageno,
style: TextStyle(fontSize: 20.0)),
Text('Ship Call #:\t' + x.scn,
style: TextStyle(fontSize: 20.0)),
Text('OR #:\t' + x.ornum,
style: TextStyle(fontSize: 20.0)),
Text(
'Amount:\t ' +
money.format(int.parse(x.payment)),
style: TextStyle(fontSize: 20.0)),
Text('Status:\t' + x.status.toUpperCase(),
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
color: x.status == 'pending'
? Colors.red
: Colors.green)),
Divider()
],
),
),
],
),
);
},
),
));
}
}
first when you fetch data in your DTO you can put bool variable inside or you can remap your DTO and put variable bool
so your variable inside somehow like this:
Map<DTO, bool>
or
DTO{
........, bool collapsed;
}
then in your code when you create your builder
final x = list[i]; >> changed to entries if you used Map [final x = mapData[i].entries.toList()]
return Container(
padding: EdgeInsets.all(20.0),
child: GestureDetector(
onTap: (){
setState({
// if you using Map
x[i] = !x.value;
// if you using DTO
x.collapsed = !x.collapsed;
});
},
child: Column(
children:[
// Your Header
Row(
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
the data will be shown first is transaction id and vessel name a arrow icon on the side when it is click it will show the other information
Text(
'Transaction ID:\t' + x.transaction_id,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
),
Text('Vessel Name:\t' + x.vesselname,
style: TextStyle(fontSize: 20.0)),
]
// Your Detail
// [if you used DTO]
if(!x.collapsed) Container(child:.......)
// [if you used Map]
if(!x.value) Container(child:......)
)
)
this is only the logic of changing the list inside to become Collapsible listView
explore ExpansionTile in flutter, I think it fits your requirement.

Flutter google_maps_flutter package blocking alertDialog

I am currently using the google_maps_flutter package, and I am placing it within a stack and overlaying it with a button. When the button is pressed, an alert should pop up.
The problem I am currently having is that it works upon first load, but if I exit the app, putting it in the background, and I reenter the app, the alertDialog is no longer showing up. It exists on the screen because I am unable to move the map, and I have to click the area where the button would normally be, but it is not visible.
Any ideas on what's going on?
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Stack(
children: <Widget>[
new Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: new Opacity(
opacity: opacity,
child: new GoogleMap(
onMapCreated: initializeMap,
options: GoogleMapOptions(
//trackCameraPosition: true,
compassEnabled: true,
myLocationEnabled: true,
),
),
),
),
new Align(
alignment: new Alignment(0, 1),
child: new GestureDetector(
onTap: () {
alert();
},
child: new Image.asset(
'assets/test.png',
height: 150.0,
fit: BoxFit.cover,
),
),
),
],
),
),
),
}
alert() {
return showCupertinoDialog(
context: context,
builder: (BuildContext context) {
return new CupertinoAlertDialog(
title: new Text("hello"),
content: new Text("hello"),
actions: <Widget>[
CupertinoDialogAction(
isDefaultAction: true,
child: Text("Ok"),
onPressed: () {
Navigator.pop(context);
}
),
CupertinoDialogAction(
child: Text("Cancel"),
onPressed: () {
Navigator.pop(context);
}
)
],
);
},
);
}
Keep in mind google_maps_flutter is a developer preview at version 0.0.3. Give it some time!

Flutter - Saving user data

I'm currently creating an application that tracks general crypto data, along with this data we also post news articles tailored to crypto enthusiasts. Every aspect of this news article data is stored in string form, from image url to date published - full list below.
I'm looking for a way to save this data to the user's device. In a perfect situation I'd just have this data saved in a JSON array, but apart from not knowing how to perform this, I'm not sure if it's the most efficient way to save this data for later display.
If you decide that JSON would be the best way of saving this data, all I need to know is how to properly manage this data into an array of different saved articles and how to import this properly into my Dart code.
An example of this code would be great, I'm looking to publish this app before the new year so I need all the help I can get. Many thanks.
This is the aforementioned data I'm looking to save / display from this source:
Source - source
Author - author
Description - description
Date Published - publishedAt
Article Title - title
Url to Article - url
Article Image - urlToImage
Edit: Trying to rework shadowsheep's answer to fit an index model
Each news widget is a new inkwell that allows a new scaffold to be built. From this scaffold you are presented with the option to save the article. On saving, the code currently just changes the value of the following strings with the title, description, URL and Image URL.
_sTitle
_sDescription
_sURL
_sURLtoImage
I would really like a way of having the database, as described by shadowsheep, saved to the user's device. This means that the saved articles will become persistent on the device despite the user closing and opening the app.
The following code is the exact use case in which I'm displaying my news data.
CarouselSlider(
items: [1,2,3,4,5,6,7,8,9,10].map((index) {
return Builder(
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.only(
top: 5.0,
bottom: 20.0,
),
child: InkWell(
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(15.0),
topRight: const Radius.circular(15.0),
),
onTap: () {
print('Opened article scaffold: "' + articles[index].title + "\"");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
backgroundColor: const Color(0xFF273A48),
elevation: 0.0,
title: Container(
width: _width*0.90,
height: 30,
padding: const EdgeInsets.only(
bottom: 5,
top: 5,
left: 10,
right: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
alignment: Alignment.center,
child: AutoSizeText(
'Published ' + DateFormat.yMMMd().format(DateTime.parse(articles[index].publishedAt)) + ", "+ DateFormat.jm().format(DateTime.parse(articles[index].publishedAt)),
overflow: TextOverflow.ellipsis,
maxLines: 1,
minFontSize: 5,
maxFontSize: 20,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Poppins',
),
),
),
),
body: Center(
child: Scaffold(
resizeToAvoidBottomPadding: false,
body: Center(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
const Color(0xFF273A48),
Colors.blueGrey
],
),
),
padding: const EdgeInsets.only(
top: 20,
left: 10,
right: 10,
bottom: 50
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
FutureBuilder<Null>(future: _launched, builder: _launchStatus),
AutoSizeText(
articles[index].title,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
maxFontSize: 30,
minFontSize: 15,
maxLines: 3,
style: TextStyle(
color: Colors.white,
fontFamily: 'Poppins',
),
),
Divider(
color: Colors.transparent,
height: 15.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
color: Colors.transparent,
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(70),
blurRadius: 50.0,
)
],
image: DecorationImage(
image: NetworkImage(articles[index].urlToImage),
fit: BoxFit.fitHeight,
),
),
height: 220,
width: 317.5,
),
Divider(
color: Colors.transparent,
height: 15.0,
),
],
),
Container(
padding: const EdgeInsets.only(
left: 20,
right: 20
),
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
child: AutoSizeText(
articles[index].description,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
maxFontSize: 30,
minFontSize: 10,
maxLines: 10,
style: TextStyle(
color: Colors.white,
fontFamily: 'Poppins',
),
),
width: _width*0.90,
height: _height*0.20,
),
Container(
padding: const EdgeInsets.all(4.0),
decoration: BoxDecoration(
color: const Color(0xFF273A48),
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(
Icons.favorite_border,
color: Colors.red
),
iconSize: 35.0,
onPressed: () {
_sTitle = articles[index].title;
_sDescription = articles[index].description;
_sURL = articles[index].url;
_sURLtoImage = articles[index].urlToImage;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => _favoritesScreen())
);
}
),
IconButton(
icon: Icon(
Icons.mobile_screen_share,
color: Colors.white,
),
iconSize: 35.0,
onPressed: () {
Share.share(
articles[index].title + "\n\nCheck out this article at:\n" + articles[index].url + "\n\nLearn more with Cryp - Tick Exchange",
);
}
),
IconButton(
icon: Icon(Icons.launch, color: Colors.lightBlueAccent),
iconSize: 32.5,
onPressed: () => setState(() { _launched = _launchInWebViewOrVC(articles[index].url);}),
),
],
),
),
],
),
),
),
),
),
)
)
);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: const Color(0xFF273A48),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(70),
offset: const Offset(5.0, 5.0),
blurRadius: 12.5,
)
],
image: DecorationImage(
alignment: Alignment.topCenter,
image: NetworkImage(articles[index].urlToImage),
fit: BoxFit.cover,
),
),
height: _height*0.35,
width: _width*0.725,
child: Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10.0, right: 10.0),
decoration: BoxDecoration(
color: const Color(0xFF273A48),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10.0),
bottomRight: Radius.circular(10.0)
),
),
height: 60.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
width: _width*0.725,
child: Text(
articles[index].title,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: TextStyle(
color: Colors.white,
fontFamily: 'Poppins',
),
),
),
),
Text(
'Published ' + DateFormat.yMMMd().format(DateTime.parse(articles[index].publishedAt)) + ", "+ DateFormat.jm().format(DateTime.parse(articles[index].publishedAt)),
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
color: Colors.blueGrey,
fontSize: 10.0,
fontFamily: 'Poppins',
),
),
],
)
),
Container(
width: 25.0,
height: 20.0,
alignment: Alignment.center,
child: Text(
"$index",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.blueGrey,
fontSize: 10.0,
fontFamily: "Poppins"
),
)
),
],
),
)
],
),
),
),
);
},
);
}).toList(),
height: 400,
autoPlay: true,
)
If you want to save data in a persitance way in Dart code and be able to use it on Android and iOS I suggest you an sqlite plugin like that:
https://github.com/tekartik/sqflite
Otherwise if you only need to save a bunch of data use the shared_preferences plugin
https://github.com/flutter/plugins/tree/master/packages/shared_preferences
These two plugins both support either Android and iOS
You are requesting a lot of code ^_^ (ain't it).
So first of all you need to get your json through an HTTP call. For that use the http flutter package:
const request = "https://newsapi.org/v2/top-headlines?sources=crypto-coins-news&apiKey=d40a757cfb2e4dd99fc511a0cbf59098";
http.Response response = await http.get(request);
debugPrint("Response: " + response.body);
Wrap it up in an async method:
void _jsonAndSqlite() async {
...
}
And in the response variable you have your full JSON.
Now you need to serialize and I suggest you this really good reading.
I've choose for this answer the Manaul JSON Decoding
Manual JSON decoding refers to using the built-in JSON decoder in
dart:convert. It involves passing the raw JSON string to the
json.decode() method, and then looking up the values you need in the
Map the method returns. It has no external
dependencies or particular setup process, and it’s good for a quick
proof of concept.
var myBigJSONObject = json.decode(response.body);
var status = myBigJSONObject['status'];
var totalResults = myBigJSONObject['totalResults'];
var myArticles = myBigJSONObject['articles'];
debugPrint("articles: " + myArticles.toString());
Now that we have articles will try to save them on Sqlite DB through Sqflite package
var myFirstArticle = myArticles[0];
var author = myFirstArticle['author'];
var title = myFirstArticle['title'];
// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'test.db');
// Delete the database
await deleteDatabase(path);
// open the database
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
// When creating the db, create the table
await db.execute(
'CREATE TABLE Article (id INTEGER PRIMARY KEY, author TEXT, title TEXT)');
});
// Insert some records in a transaction
await database.transaction((txn) async {
int id1 = await txn.rawInsert(
'INSERT INTO Article(author, title) VALUES("$author", "$title")');
debugPrint('inserted1: $id1');
});
And that's it! Have fun studing and coding. Read the articles I've posted for you for JSON serailization and play around with my code, and trying to adding some other best practices they may better fit your needs. This is just a quick playground to, well, play with.
So I ended up with this method:
[...]
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
[...]
void _jsonAndSqlite() async {
const request =
"https://newsapi.org/v2/top-headlines?sources=crypto-coins-news&apiKey=d40a757cfb2e4dd99fc511a0cbf59098";
http.Response response = await http.get(request);
debugPrint("Response: " + response.body);
var myBigJSONObject = json.decode(response.body);
var status = myBigJSONObject['status'];
var totalResults = myBigJSONObject['totalResults'];
var myArticles = myBigJSONObject['articles'];
debugPrint("articles: " + myArticles.toString());
var myFirstArticle = myArticles[0];
var author = myFirstArticle['author'];
var title = myFirstArticle['title'];
// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'test.db');
// Delete the database
await deleteDatabase(path);
// open the database
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
// When creating the db, create the table
await db.execute(
'CREATE TABLE Article (id INTEGER PRIMARY KEY, author TEXT, title TEXT)');
});
// Insert some records in a transaction
await database.transaction((txn) async {
int id1 = await txn.rawInsert(
'INSERT INTO Article(author, title) VALUES("$author", "$title")');
debugPrint('inserted1: $id1');
});
}

many json loading in the same screen, how to await one and continue?

I have a screen with multiples json request, but it is loading all in the same time, i want to when finish one start the another until the end.
new CustomScrollView(
cacheExtent: height * 5,
slivers: [
new SliverList(
delegate: new SliverChildListDelegate(
[
new RelatorioVendPeriodoAPeriodo(),
new RelatorioDiasDaSemanas(),
new RelatorioVendasTotalidasPorPeriodo(),
new RelatorioDasVendasTotsProdutos(),
new RelatorioMensals(),
]
)
)
]
),
this classes loads a json request, how to divide and await one to start other?
Here one of this classes return method:
Widget build(BuildContext context) {
double height = (MediaQuery.of(context).size.height) - kRadialReactionRadius - kToolbarHeight;
return new Container(
height: height,
padding: new EdgeInsets.only(left: 5.0, right: 5.0),
child: new Card(
elevation: 10.0,
child:
new Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new ListTile(
trailing:
_buildCounterButton(),
title: new Center(child: new Text('FATURAMENTO MENSAL', style: new TextStyle(fontWeight: FontWeight.bold))),
subtitle: new Icon(Icons.info),
onTap: _showDialog,
),
new FutureBuilder<List<RelatorioMensal>>(
future: fetchRelatorioMensal(new http.Client(), "", '$dateFinal1Sem'),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? new porVendaMensal(listVendasMensais: snapshot.data,)
: new Center(child: new CircularProgressIndicator());
}
),
],),]
),
),
);
}