Flutter - Delaying json requests to do once per time - json

i'm trying to do a Dashboard with multiples jsons requests, but i want that request work one per one, like when finish first request start the second, when finish second start the third when finish third start the N.
my list code:
new CustomScrollView(
cacheExtent: height * 6,
slivers: [
new SliverList(
delegate: new SliverChildListDelegate(
[
new RelatorioVendPeriodoAPeriodo(),
new RelatorioMensals(),
new RelatorioDiasDaSemanas(),
new RelatorioVendasTotalidasPorPeriodo(),
new RelatorioDasVendasTotsProdutos(),
]
)
)
]
),
this new classes calls, returns for me request. Anyone knows how to delay it?

First, the parent widget should return a progress bar when the necessary data is not available.
A service will be called an initState to fetch data from the backend. when data is ready setState() will be called to redraw the widget.
Look at this example:
class _TestWidgetState extends State<TestWidget> {
var data;
#override
void initState() {
data = NetworkService.getData().then((data) {
setState(() {
this.data = data;
});
});
}
#override
Widget build(BuildContext context) {
if (data == null) {
return CircularProgressIndicator();
} else {
return
new CustomScrollView(
cacheExtent: height * 6,
slivers: [
new SliverList(
delegate: new SliverChildListDelegate(
[
new RelatorioVendPeriodoAPeriodo(data: data),
new RelatorioMensals(data: data),
new RelatorioDiasDaSemanas(data: data),
new RelatorioVendasTotalidasPorPeriodo(data: data),
new RelatorioDasVendasTotsProdutos(data: data),
]
)
)
]
);
}
}
}
class NetworkService {
final JsonDecoder _decoder = new JsonDecoder();
static String data1;
static String data2;
static getData() async {
if (data1 == null || data2 == null) {
await fetchFromServer();
}
return {'data1': data1, 'data2': data2};
}
static fetchFromServer() async {
data1 = (await http.get('url')).body;
data2 = (await http.get('url')).body;
}
}

Future.delayed(const Duration(milliseconds: 500), () {
print(" This line is executed after 5 seconds");
});

Related

What push data payload structure I need for this handler? (Flutter)

I am using FLutterFlow to build an app and my coding level is beginner. I need to create a valid push data payload structure (JSON) at backend side to pass to app two parameters:
app page (tab) name that should be opened when user taps on push (is called "initialPageName" in code below)
push unique id assigned by backend (is called "pushGUID" in code below)
Below is push handler code that is under the hood of FlutterFlow web app builder, I can not change it. I know it works, because when I use FlutterFlow web push sender and fill in "initial page" and "push GUID" everything works fine. But when I send push from my backend using FCM HTTP API I get only notification itself, data payload with "push GUID" is not handled correctly.
import 'dart:async';
import 'dart:convert';
import 'serialization_util.dart';
import '../backend.dart';
import '../../flutter_flow/flutter_flow_theme.dart';
import '../../flutter_flow/flutter_flow_util.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import '../../index.dart';
import '../../main.dart';
final _handledMessageIds = <String?>{};
class PushNotificationsHandler extends StatefulWidget {
const PushNotificationsHandler({Key? key, required this.child})
: super(key: key);
final Widget child;
#override
_PushNotificationsHandlerState createState() =>
_PushNotificationsHandlerState();
}
class _PushNotificationsHandlerState extends State<PushNotificationsHandler> {
bool _loading = false;
Future handleOpenedPushNotification() async {
if (isWeb) {
return;
}
final notification = await FirebaseMessaging.instance.getInitialMessage();
if (notification != null) {
await _handlePushNotification(notification);
}
FirebaseMessaging.onMessageOpenedApp.listen(_handlePushNotification);
}
Future _handlePushNotification(RemoteMessage message) async {
if (_handledMessageIds.contains(message.messageId)) {
return;
}
_handledMessageIds.add(message.messageId);
if (mounted) {
setState(() => _loading = true);
}
try {
final initialPageName = message.data['initialPageName'] as String;
final initialParameterData = getInitialParameterData(message.data);
final parametersBuilder = parametersBuilderMap[initialPageName];
if (parametersBuilder != null) {
final parameterData = await parametersBuilder(initialParameterData);
context.pushNamed(
initialPageName,
params: parameterData.params,
extra: parameterData.extra,
);
}
} catch (e) {
print('Error: $e');
} finally {
if (mounted) {
setState(() => _loading = false);
}
}
}
#override
void initState() {
super.initState();
handleOpenedPushNotification();
}
#override
Widget build(BuildContext context) => _loading
? Container(
color: Colors.white,
child: Image.asset(
'assets/images/logo.png',
fit: BoxFit.contain,
),
)
: widget.child;
}
class ParameterData {
const ParameterData(
{this.requiredParams = const {}, this.allParams = const {}});
final Map<String, String?> requiredParams;
final Map<String, dynamic> allParams;
Map<String, String> get params => Map.fromEntries(
requiredParams.entries
.where((e) => e.value != null)
.map((e) => MapEntry(e.key, e.value!)),
);
Map<String, dynamic> get extra => Map.fromEntries(
allParams.entries.where((e) => e.value != null),
);
static Future<ParameterData> Function(Map<String, dynamic>) none() =>
(data) async => ParameterData();
}
final parametersBuilderMap =
<String, Future<ParameterData> Function(Map<String, dynamic>)>{
'PhoneAuth': ParameterData.none(),
'smsVerify': (data) async => ParameterData(
allParams: {
'phoneNumber': getParameter<String>(data, 'phoneNumber'),
},
),
'MainPage': (data) async => ParameterData(
allParams: {
'pushGUID': getParameter<String>(data, 'pushGUID'),
},
),
'Campaign': ParameterData.none(),
'LoyaltyPoints': ParameterData.none(),
'OnTheMap': ParameterData.none(),
'NewCollections': ParameterData.none(),
'Notifications': ParameterData.none(),
};
Map<String, dynamic> getInitialParameterData(Map<String, dynamic> data) {
try {
final parameterDataStr = data['parameterData'];
if (parameterDataStr == null ||
parameterDataStr is! String ||
parameterDataStr.isEmpty) {
return {};
}
return jsonDecode(parameterDataStr) as Map<String, dynamic>;
} catch (e) {
print('Error parsing parameter data: $e');
return {};
}
}
My guess looking at the code above is that I should use nested JSON like this:
{
"message":{
"notification":{
"body" : "my body",
"title" : "my title",
},
"data" : {
"initialPage":"mainPage",
"params":[
{"pushGUID":"1231231231"}
]
}
}
}
But as I mentioned my Futter code level is beginner, so please have a look at the handler code and correct my JSON structure, thanks for any advice.

How do I initialize my json response in another class that depends on a search input in flutter?

this is my first question here on stackoverflow.
I'm working on my first real app after attending a few CS classes at University and some courses on Udemy. So I'm lacking a lot of software engineering knowledge.
My goal: I want to build a search for stocks by using an external API endpoint. For that, I have created 4 dart files to handle the searchscreen with inputs (My UI), networking, parsing, and basically returning the data.
My NetworkAPI class to handle all sorts of network requests looks like this. I'm trying to use the jsonDecode already here and returning that. This class waits for an URL that will be put together in another class (financeData):
class NetworkAPI {
final String url;
NetworkAPI(this.url);
Future getData() async {
http.Response response = await http.get(url);
if (response.statusCode == 200) {
String data = response.body;
return jsonDecode(data);
} else {
print(response.statusCode);
}
}
}
This is basically the Json I want to parse. If I understood the theory correctly it's a map with a list of objects.
{
"bestMatches": [
{
"1. symbol": "TESO",
"2. name": "Tesco Corporation USA",
"3. type": "Equity",
"4. region": "United States",
"5. marketOpen": "09:30",
"6. marketClose": "16:00",
"7. timezone": "UTC-04",
"8. currency": "USD",
"9. matchScore": "0.8889"
}
{....}
]
}
To parse this, I saw some really good explanations here on stack overflow. I'm basically trying to retrieve the information I'm interested in.
class SearchOutput {
final List<BestMatch> bestMatches;
SearchOutput({this.bestMatches});
factory SearchOutput.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson['bestMatches'] as List;
print(list.runtimeType);
List<BestMatch> searchResultList = list.map((i) => BestMatch.fromJson(i)).toList();
return SearchOutput(
bestMatches: searchResultList,
);
}
}
class BestMatch {
String symbol;
String name;
String type;
String region;
String currency;
BestMatch({
this.symbol,
this.name,
this.type,
this.region,
this.currency,
});
factory BestMatch.fromJson(Map<String, dynamic> parsedJson){
return BestMatch(
symbol: parsedJson["1. symbol"],
name: parsedJson["2. name"],
type: parsedJson["3. type"],
region: parsedJson["4. region"],
currency: parsedJson["8. currency"],
);
}
}
Now I created a class with a method that should return all my data and format it into a list. The URL still needs an searchInput, which will be handed over from a TextField Widget in the UI.
const apiKey = 'demo';
const alphaVantageSearchUrl =
'https://www.alphavantage.co/query?function=SYMBOL_SEARCH';
class FinanceData {
Future<dynamic> getSearchData(String searchInput) async {
var url = '$alphaVantageSearchUrl&keywords=$searchInput&apikey=$apiKey';
NetworkAPI networkAPI = NetworkAPI(url);
var searchData = await networkAPI.getData();
SearchOutput searchOutput = new SearchOutput.fromJson(searchData);
return searchOutput;
}
}
Testing with some print statements seems to fullfill my goal of being able to access the data. For example printing out the name of the second object out of my response.
print(searchOutput.bestMatches[1].name);
The last file is my UI where we have a TextField, that I push to the financeData class in order to build the URL. Currently, my goal would be, to be able to show just the name of any given object in my response in the UI. I have no idea how to initialize my financeDate and how to use the return from my finaceData class in the UI. (I took some design styles out of the code snippet).
class SearchScreenWatchlist extends StatefulWidget {
#override
_SearchScreenWatchlistState createState() => _SearchScreenWatchlistState();
}
class _SearchScreenWatchlistState extends State<SearchScreenWatchlist> {
String searchInput;
FinanceData financeData = FinanceData();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Container(
child: TextField(
onChanged: (value) {
searchInput = value;
},
),
),
TextButton(
onPressed: () {
financeData.getSearchData(searchInput);
setState(() {
});
},
child: Text('Search')),
Text(('Search Results for: $searchInput')),
Container(child: Text('**SHOW HERE THE NAME**')),
],
),
);
}
}
It would be my goal to show in the last container the name on any given object from my response for example RESPONSE.name[1]. Later on I will try to iterate throw all the objects and show a list of all names of the response.
Thanks a lot! I really appreciate your help!
I think changing SearchScreenWatchlist to the following should display the name of the first bestMatches entry after you pressed the Search button (if I didn't miss something).
Make sure to look further into setState and initState (And the StatefulWidget lifecycle in general). Also it may not be the most elegant way to initialize FinanceData() and SearchOutput() this way - However, awesome starter project!
class SearchScreenWatchlist extends StatefulWidget {
#override
_SearchScreenWatchlistState createState() => _SearchScreenWatchlistState();
}
class _SearchScreenWatchlistState extends State<SearchScreenWatchlist> {
String searchInput;
FinanceData financeData;
SearchOutput searchOutput;
#override
initState() {
super.initState();
financeData = FinanceData();
searchOutput = SearchOutput();
}
_handleButtonPress() async {
final fetchedSearchOutput = await financeData.getSearchData(searchInput);
setState(() {
searchOutput = fetchedSearchOutput;
});
}
_buildSearchResult() {
if(searchOutput.bestMatches != null && searchOutput.bestMatches.isNotEmpty) {
return Text(searchOutput.bestMatches.first.name);
}
else {
return Text("No data fetched");
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Container(
child: TextField(
onChanged: (value) {
setState(() {
searchInput = value;
});
},
),
),
TextButton(
onPressed: () => _handleButtonPress(),
child: Text('Search'),
),
Text(('Search Results for: $searchInput')),
Container(
child: _buildSearchResult(),
),
],
),
);
}
}

How can I parse json data from websocket server in flutter?

The WebSocket server is supposed to shoot json data as soon as it goes up, and I want to create a StreamBuilder that updates the data as it shoots me FutureBuilder has received async and wait http.get, and how do I make a Stream for my stream builder?
Here is the futurebuilder when I receive information from http server!(for all information, no realtime)
I want to receive information like this by streambuilder from websocket server for realtime!
class BallInformationWidget extends StatefulWidget {
#override
BallInformationWidgetState createState() => BallInformationWidgetState();
}
class BallInformationWidgetState extends State<BallInformationWidget> {
#override
Widget build(BuildContext context) {
return FutureBuilder<List<BallInformation>>(
future: getHttpBallInfo(urlPrefix),
builder: (context, snapshot) {
print('http data : ${snapshot.data}');
print('http length : ${snapshot.data.length}\n');
print('http type : ${snapshot.data[0].id.runtimeType}\n');
BallInformation ballInfo = snapshot.data[0]; // 공하나 객체 선언 후에 for 문?
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: Text(snapshot.hasData ? '${ballInfo.id}' : 'Loading...'),
);
},
);
}
}
class BallInformation {
int id;
double speed;
String result;
Map trajectoryParameter;
BallInformation(this.id, this.speed, this.result, this.trajectoryParameter);
BallInformation.fromJson(Map<String, dynamic> data) {
this.id = data['id'];
this.speed = data['speed'];
this.result = data['result'];
this.trajectoryParameter = data['trajectory_parameter'];
}
}
Future<List<BallInformation>> getHttpBallInfo(String url) async {
http.Response response = await http.get(url);
String responseBody = response.body;
var dataS = json.decode(responseBody);
List<BallInformation> ballInformation = [];
// If I receive json(only one information
ballInformation.add(BallInformation.fromJson(dataS));
// If I receive json(List, more than 1 information)
// for (var data in dataS){
// ballInformation.add(BallInformation.fromJson(data));
// }
return ballInformation;
}
The standart method for this is json.decode(snapshot.data). This will return a map of your json data in the request.

FormatException: Unexpected character (at character 1) <!DOCTYPE html> Flutter Google Sheets

I'm getting this weird response while using http in Flutter/Dart. Similar code is working fine with other APIs endpoints but not this. Although the link has jSON data not any other format.
I have already check the following links and NONE of them is related to mine:
formatexception (formatexception: unexpected character (at character 1) json
Exception: FormatException: Unexpected character (at character 1)
Exception
Explanation
The exception I'm getting is similar. And I know that it is return HTML instead of jSON. But my link is NOT an HTML. Its a array of jSON Objects
Code
Apps Script Code for Google Sheets
function doGet(request) {
var sheet = SpreadsheetApp.openById("1CBPpqvdUpPaYMjxpX_9-ywMsErT06fD6AfzASWBFnnk");
var values = sheet.getActiveSheet().getDataRange().getValues();
var data = [];
for (var i = values.length - 1; i > 0; i--) {
var row = values[i];
var story = {};
story['Latitude'] = row[5];
story['Longitude'] = row[6];
console.log(story['Longitude'], story['Longitude']);
data.push(story);
}
return ContentService
.createTextOutput(JSON.stringify(data))
.setMimeType(ContentService.MimeType.JSON);
}
Model Class
class StoryList {
final List<Story> stories;
StoryList({this.stories});
factory StoryList.fromJson(List<dynamic> parsedJson) {
List<Story> story = new List<Story>();
story = parsedJson.map((i) => Story.fromJSON(i)).toList();
return new StoryList(stories: story);
}
}
class Story {
final String longitude;
final String latitude;
Story({this.latitude, this.longitude});
factory Story.fromJSON(Map<String, dynamic> json) {
return Story(
longitude: json['Longitude'],
latitude: json['Latitude'],
);
}
}
Controller Class
You won't be able to access the link its restricted for organization use only
class StoryController {
Future<StoryList> getCountryData() async {
String url =
'https://script.google.com/a/macros/storius.app/s/AKfycbyzx4kIlVdTC9QVVBovVfWMDFWdk9noomDJV4XcyDApnsMYTe68u0mL/exec';
final response = await http.get(url);
if (response.statusCode == 200) {
final jsonRes = json.decode(response.body);
return StoryList.fromJson(jsonRes);
} else {
throw Exception("Failed due to Network Error");
}
}
}
View Class
For the time being I'm only getting Longitude for testing purposes.
class HomeView extends StatefulWidget {
#override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: StoryController().getCountryData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data.stories[index].longitude),
);
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
));
}
}
As per our Discord discussion, when you printed response.body at my suggestion you see that you are getting an html response from the url, not json as you expected.
The problem is with authentication on the linked website rather than with the Flutter/Dart code. You need to resolve that authentication issue.
It is recommended that when testing new code that accesses a database or a url to always print out, or use a debugger to view, the returned data. Never assume you are getting what you expect.

Flutter: Trying to access location data in background using location and workManager plugin

Issue in brief:
trying to access location data of the user in background using location and workManager plugin.
Currently with the code mentioned below i am able to access the location information if the application is open, Since callbackDispatcher is a top level function i am not able to call the location plugin.
location plugin works when a call is done inside of the class. I am trying a way to access _getlocation() from callbackDispatcher, I am getting PlatformException(NO_ACTIVITY).
Things I have tried:
found few other guys facing similar issue here, here and here
Tired all these steps and no luck.
import 'package:flutter/material.dart';
import 'package:location/location.dart';
import 'package:workmanager/workmanager.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
Location location = new Location();
void callbackDispatcher() {
Workmanager.executeTask((task, inputData) {
if (task == "simplePeriodicTask") {
print("task working");
_getLocation();
}
return Future.value(true);
});
}
LocationData _location;
String _error;
double lat;
double long;
_getLocation() async {
_error = null;
try {
var _locationResult = await location.getLocation();
_location = _locationResult;
lat = _location.latitude;
long = _location.longitude;
} on PlatformException catch (err) {
_error = err.code;
}
if (_error == null) {
// _check();
print(lat);
} else {
//dialog
print(_error);
}
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
Workmanager.initialize(
callbackDispatcher, // The top level function, aka callbackDispatcher
isInDebugMode:
true // If enabled it will post a notification whenever the task is running. Handy for debugging tasks
);
_checkPermissions();
}
// Permission for location
PermissionStatus _permissionGranted;
// final Location location = new Location();
_checkPermissions() async {
PermissionStatus permissionGrantedResult = await location.hasPermission();
setState(() {
_permissionGranted = permissionGrantedResult;
});
if (_permissionGranted == PermissionStatus.DENIED) {
_requestPermission();
} else if (_permissionGranted == PermissionStatus.GRANTED) {
_checkService();
}
}
_requestPermission() async {
if (_permissionGranted != PermissionStatus.GRANTED) {
PermissionStatus permissionRequestedResult =
await location.requestPermission();
setState(() {
_permissionGranted = permissionRequestedResult;
});
if (permissionRequestedResult != PermissionStatus.GRANTED) {
return;
} else if (permissionRequestedResult == PermissionStatus.GRANTED) {
_checkService();
}
}
}
//Permission ends
//services enabled function
bool _serviceEnabled;
_checkService() async {
bool serviceEnabledResult = await location.serviceEnabled();
setState(() {
_serviceEnabled = serviceEnabledResult;
});
if (_serviceEnabled == false) {
_requestService();
} else {
// _getLocation();
}
}
_requestService() async {
if (_serviceEnabled == null || !_serviceEnabled) {
bool serviceRequestedResult = await location.requestService();
setState(() {
_serviceEnabled = serviceRequestedResult;
});
if (!serviceRequestedResult) {
return;
} else {
// _getLocation();
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dart'),
),
body: Column(children: <Widget>[
RaisedButton(
child: Text('get Location'),
onPressed: () {
Workmanager.registerPeriodicTask(
"2",
"simplePeriodicTask",
// When no frequency is provided the default 15 minutes is set.
// Minimum frequency is 15 min. Android will automatically change your frequency to 15 min if you have configured a lower frequency.
);
print('task registered');
_getLocation();
}),
RaisedButton(
onPressed: () async {
await Workmanager.cancelAll();
print('task Destroyd');
},
child: Text("cancel"),
),
]),
);
}
}
Trying to access _getlocation() from callbackDispatcher();
Any help on this is greatly appreciated.
I was facing same issue recently. location package not work with WorkManager plugin, I dont know the reason but here is my solution;
/// This Function calls only from WorkManager
/// Used GeoLocator instead of Location package due to PlatformException(NO_ACTIVITY) error throwing
Future<String> getPlaceMarkLocationWhileAppOff() async {
Geolocator geoLocator = Geolocator()..forceAndroidLocationManager = true;
var _position = await geoLocator.getCurrentPosition(
// desiredAccuracy: LocationAccuracy.high,
);
var value = await geoLocator.placemarkFromCoordinates(_position.latitude, _position.longitude);
return _placeMark = "${value.first.subLocality}\n${value.first.subAdministrativeArea}";
}
Used Geolocator package when app offline and used Location package when app online..
I hope it will help..