Load and read data from Json file - dart

I create simple app get data of marker from json file and draw them.
The code below is get data from data.json and add to the list of marker.
I got problem. I can't get data from json file and add it to my marker list. How can I do that?
My main.dart code
class MapSample extends StatefulWidget {
#override
State<MapSample> createState() => MapSampleState();
}
class MapSampleState extends State<MapSample> {
#override
void initState() {
var location = Location();
FutureBuilder(
future:
DefaultAssetBundle.of(context).loadString('assets/data.json'),
builder: (context, snapshot) {
// Decode the JSON
var new_data = json.decode(snapshot.data.toString());
for (var i = 0; i < new_data.length; i++) {
location = Location(
id: new_data[i]['id'],
lat: new_data[i]['x'],
long: new_data[i]['y'],
);
locations.add(location);
//print(location.lat);
}
});
super.initState();
}
}
My data.json
[{
"rownum": 1,
"id": "E3E0D2C5-CB82-4AF3-8D5D-4CD323560F59",
"x": 10.99803453,
"y": 106.65676933,
}, {
"rownum": 2,
"id": "5FFB6736-7D1F-4B40-A397-32EB3128BC30",
"x": 10.99793271,
"y": 106.65666751,
},

I think this is what you are looking for.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
void main() {
runApp(Test());
}
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
Future _future;
List<Location> locations;
Future<String> loadJson() async =>
await rootBundle.loadString('assets/data.json');
#override
void initState() {
_future = loadJson();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: _future,
builder: (context, snapshot) {
if (snapshot.hasData) {
for (var v in snapshot.data) {
locations.add(Location(
id: v['id'],
lat: v['x'],
long: v['y'],
));
}
return Text(snapshot.data);
} else {
return CircularProgressIndicator();
}
}),
),
);
}
}
class Location {
final String id;
final double lat;
final double long;
Location({this.id, this.lat, this.long});
}

Try this.
You have to add the data.json file in assests.
Then add in to pubspec.yaml file.
assets:
- assets/data.json
Then add this below code.
String jsonData = await DefaultAssetBundle.of(context).loadString("assets/data.json");
final jsonResult = json.decode(jsonData);

Related

The following TypeErrorImpl was thrown building GameScreen

I got this error on terminal
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
╞═══════════════════════════════════════════════════════════ The
following TypeErrorImpl was thrown building GameScreen(dirty,
dependencies: [_InheritedProviderScope<RoomDataProvider?>], state:
_GameScreenState#df23f): type 'Null' is not a 'bool' in boolean expression The relevant error-causing widget was: GameScreen
This is my code:
import 'package:flutter/material.dart';
import 'package:game/provider/room_data_provider.dart';
import 'package:game/resources/socket_method.dart';
import 'package:provider/provider.dart';
import '../viiews/waiting_lobby.dart';
class GameScreen extends StatefulWidget {
static String routeName = '/game';
const GameScreen({Key? key}) : super(key: key);
#override
State<GameScreen> createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
final SocketMethods _socketMethods = SocketMethods();
#override
void initState() {
super.initState();
_socketMethods.updateRoomListener(context);
_socketMethods.updatePlayerStateListener(context);
// _socketMethods.pointIncreaseListener(context);
// _socketMethods.endGameListener(context);
}
#override
Widget build(BuildContext context) {
RoomDataProvider roomDataProvider = Provider.of<RoomDataProvider>(context);
return Scaffold(
body: roomDataProvider.roomData['isJoin']
? const WaitingLobby()
: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
// const Scoreboard(),
// const TicTacToeBoard(),
Text(
'${roomDataProvider.roomData['turn']['nickname']}\'s turn'),
],
),
),
);
}
}
room_data_provider.dart
import 'package:flutter/material.dart';
import 'package:game/models/player.dart';
class RoomDataProvider extends ChangeNotifier {
Map<String, dynamic> _roomData = {};
Player _player1 =
Player(nickname: "", socketID: "", points: 0, playerType: "X");
Player _player2 =
Player(nickname: "", socketID: "", points: 0, playerType: "O");
Map<String, dynamic> get roomData => _roomData;
Player get player1 => _player1;
Player get player2 => _player2;
void updateRoomData(Map<String, dynamic> data) {
_roomData = data;
notifyListeners();
}
void updatePlayer1(Map<String, dynamic> player1Data) {
_player1 = Player.fromMap(player1Data);
notifyListeners();
}
void updatePlayer2(Map<String, dynamic> player2Data) {
_player2 = Player.fromMap(player2Data);
notifyListeners();
}
}
index.js
socket.on("joinRoom", async ({ nickname, roomId }) => {
try {
if (!roomId.match(/^[0-9a-fA-F]{24}$/)) {
socket.emit("errorOccurred", "Please enter a valid room ID.");
return;
}
let room = await Room.findById(roomId);
if (room.isJoin) {
let player = {
nickname,
socketID: socket.id,
playerType: "O",
};
socket.join(roomId);
room.players.push(player);
room.isJoin = false;
room = await room.save();
io.to(roomId).emit("joinRoomSuccess", room);
io.to(roomId).emit("updatePlayers", room.players);
io.to(roomId).emit("updateRoom", room);
} else {
socket.emit(
"errorOccurred",
"The game is in progress, try again later."
);
}
} catch (e) {
console.log(e);
}
});
How can I solve this issue ?
Thanks for any help you can provide

StateError (Bad state: No element) on IOS only

This error does not occur on Android or web but only on IOS. It seem very trivial but I can't figure out what's wrong.
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'dart:convert';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class ScanQrPage extends StatefulWidget {
#override
_ScanQrPageState createState() => _ScanQrPageState();
}
class _ScanQrPageState extends State<ScanQrPage> {
final qrKey = GlobalKey();
late QRViewController qrViewController;
late Barcode barcode;
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is iOS.
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
qrViewController.pauseCamera();
} else if (Platform.isIOS) {
qrViewController.resumeCamera();
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
Navigator.of(context).pop("");
return new Future(() => true);
},
child: Scaffold(
body: Stack(
children: [
buildQrView(context),
],
),
),
);
}
Widget buildQrView(BuildContext context) {
return QRView(
onQRViewCreated: onQRViewCreated,
key: qrKey,
overlay: QrScannerOverlayShape(
cutOutSize: MediaQuery.of(context).size.width * 0.8),
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
);
}
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('no Permission')),
);
}
}
#override
void dispose() {
qrViewController.dispose();
super.dispose();
}
void onQRViewCreated(QRViewController qrViewController) {
setState(() {
this.qrViewController = qrViewController;
});
qrViewController.scannedDataStream.listen((event) {
setState(() {
this.barcode = event;
if (Platform.isAndroid) {
qrViewController.pauseCamera();
} else if (Platform.isIOS) {
qrViewController.resumeCamera();
}
String rawData = event.code;
Uri data = Uri.dataFromString(rawData);
String para1 = data.queryParameters["buy"] ??
""; //get parameter with attribute "para1"
Codec<String, String> stringToBase64 = utf8.fuse(base64);
if (para1 != "") {
placer = stringToBase64.decode(para1);
}
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
Navigator.pop(context, placer);
});
});
});
}
}
I've tried all the solutions with the same error found on stackoverflow (addPostFrameCallback and Future(Duration.zero)) but none of them are exactly the same and does not seem to fix my problem.
I don't think I have having the same issue as any of the other questions.
The exception is happening on the Navigator.pop(context, placer);
Does anyone have any idea how to overcome this?
Why does this only happen on IOS?

Flutter don't update UI from iOS using setState() method

I am invoking a method from native Swift code by using the platform channel like this:
channel.invokeMethod(METHOD_NAME, arguments: STRING_ARGUMENT)
in my Flutter class I handle the respective method call by using a callback
platform.setMethodCallHandler(_receiveFromHost);
The setMethodCallHandler() requires the callback to return a Future and I set state in _receiveFromHost method in Dart.
Problem is that my UI is not updated when Swift invokes the callback. Why?
call.method catch method string, state is set, but UI don't update.
video
This is my code in Swift:
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterViewController = FlutterViewController(engine: flutterEngine!, nibName: nil, bundle: nil)
let channel = FlutterMethodChannel(name: "flutter_apple_pay", binaryMessenger: flutterViewController.binaryMessenger)
channel.invokeMethod("sendDidFinishAdding", arguments: "payment success")
And this is my code in Flutter:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'dart:convert';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text("Native Code from Dart"),
),
body: new MyHomePage(title: ""),
);
}
}
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 _state = "Waiting results...";
static const platform = const MethodChannel("flutter_apple_pay");
_MyHomePageState() {
platform.setMethodCallHandler(_receiveFromHost);
}
// #override
// void initState() {
// platform.setMethodCallHandler(_receiveFromHost);
// super.initState();
// }
Future<dynamic> _receiveFromHost(MethodCall call) async {
List certificatesBase64Encoded;
String nonceBase64Encoded;
String nonceSignatureBase64Encoded;
String state;
try {
print(call.method);
if (call.method == "sendGenerateRequestWithData") {
final String data = call.arguments;
final jData = jsonDecode(data);
certificatesBase64Encoded = jData['certificatesBase64Encoded'];
nonceBase64Encoded = jData['nonceBase64Encoded'];
nonceSignatureBase64Encoded = jData['nonceSignatureBase64Encoded'];
print(certificatesBase64Encoded);
print(nonceBase64Encoded);
print(nonceSignatureBase64Encoded);
state = "sendGenerateRequestWithData";
platform.invokeMethod("SendTokenizationData", "TokenizationDataString");
} else if (call.method == "sendDidFinishAdding") {
final String result = call.arguments;
print(result);
state = result;
}
} on PlatformException catch (e) {
print(e);
}
setState(() {
_state = state;
});
print(_state);
}
Future<void> _checkCardState() async {
String cardState;
const primaryAccountIdentifiers = ["a", "b"];
try {
final String result = await platform.invokeMethod(
"checkCardState", primaryAccountIdentifiers);
cardState = result;
} on PlatformException catch (e) {
cardState = "Failed to Invoke: '${e.message}'.";
}
setState(() {
_state = cardState;
});
}
Future<void> _startApplePay() async {
const _cardNetwork = "cn/AMEX";
const _cardHolderName = "pero peric";
const _primaryAccountIdentifier = "a";
const _primaryAccountSuffix = "1234";
const _localizedDescription = "AMEX";
Map<String, dynamic> resultMap = Map();
resultMap['cardNetwork'] = _cardNetwork;
resultMap['cardHolderName'] = _cardHolderName;
resultMap['primaryAccountIdentifier'] = _primaryAccountIdentifier;
resultMap['primaryAccountSuffix'] = _primaryAccountSuffix;
resultMap['localizedDescription'] = _localizedDescription;
platform.invokeMethod("startApplePay", resultMap);
}
#override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
child: Text('Check Card State'),
onPressed: _checkCardState,
),
ElevatedButton(
child: Text('Start Apple Pay'),
onPressed: _startApplePay,
),
Text(_state),
],
),
),
);
}
}
Thanks!

Get data from JSON and add into the List on initState()

I have JSON file below.
Data.json
[{
"rownum": 1,
"total": 10.99793271,
"total2": 106.65666751,
}, {
"rownum": 2,
"total": 10.99793271,
"total2": 106.65666751,
}]
and the class Item and List
List <Item> item;
class Item {
String row;
String total;
String total2;
Student({this.row, this.total, this.total2});
}
How can I get data from data.json and add them into List <Item> item on the initState()?
Like this
class MyAppState extends State<MyApp> {
#override
void initState() {
Future<String> _loadAStudentAsset() async {
return await rootBundle.loadString('assets/data.json');
}
//....some code to add value into list
super.initState();
}
That solution is also valid for you:
Flutter: How to display a short text file from assets on screen of phone?
If we make another example with same template:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
void main() {
runApp(Test());
}
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
Future _future;
Future<String> loadString() async =>
await rootBundle.loadString('assets/data.json');
#override
void initState() {
_future = loadString();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Text('Loading...');
}
List<dynamic> parsedJson = jsonDecode(snapshot.data);
items = parsedJson.map((element) {
return Item(
row: element['rownum'].toString(),
total: element['total'].toString(),
total2: element['total2'].toString(),
);
}).toList();
;
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Column(
children: <Widget>[
Text(item.row),
Text(item.total),
Text(item.total2),
],
);
},
);
},
),
),
);
}
}
List<Item> items;
class Item {
String row;
String total;
String total2;
Item({this.row, this.total, this.total2});
}
class Item {
static final String db_row = "rownum";
static final String db_total = "total";
static final String db_total2 = "total2";
int row;
double total;
double total2;
Item({this.row, this.total, this.total2});
Item.fromMap(Map map) {
this.row = map[Item.db_row];
this.total = map[Item.db_total];
this.total2 = map[Item.db_total2];
}
Map toMap() =>
{Item.db_row: row, Item.db_total: total, Item.db_total2: total2};
static List<Item> fromMapList(mapList) {
List<Item> items = new List();
new List.from(mapList).forEach((mapItem) {
items.add(Item.fromMap(mapItem));
});
return items;
}
}
And
List <Item> items = Item.fromMapList(await rootBundle.loadString('assets/data.json'));

Flutter set startup page based on Shared Preference

I've been trying without success to load different pages according to my Shared Preference settings.
Based on several posts found in stackoverflow, i end up with the following solution:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:testing/screens/login.dart';
import 'package:testing/screens/home.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Widget page = Login();
Future getSharedPrefs() async {
String user = Preferences.local.getString('user');
if (user != null) {
print(user);
this.page = Home();
}
}
#override
void initState() {
super.initState();
this.getSharedPrefs();
}
#override
Widget build(BuildContext context) {
return MaterialApp(home: this.page);
}
}
class Preferences {
static SharedPreferences local;
/// Initializes the Shared Preferences and sets the info towards a global variable
static Future init() async {
local = await SharedPreferences.getInstance();
}
}
The variable user is not null because the print(user) returns a value as expected, but the login screen is always being opened.
Your problem is that your build method returns before your getSharedPrefs future is complete. The getSharedPrefs returns instantly as soon as it's called because it's async and you're treating it as a "Fire and Forget" by not awaiting. Seeing that you can't await in your initState function that makes sense.
This is where you want to use the FutureBuilder widget. Create a Future that returns a boolean (or enum if you want more states) and use a future builder as your home child to return the correct widget.
Create your future
Future<bool> showLoginPage() async {
var sharedPreferences = await SharedPreferences.getInstance();
// sharedPreferences.setString('user', 'hasuser');
String user = sharedPreferences.getString('user');
return user == null;
}
When user is null this will return true. Use this future in a Future builder to listen to the value changes and respond accordingly.
#override
Widget build(BuildContext context) {
return MaterialApp(home: FutureBuilder<bool>(
future: showLoginPage(),
builder: (buildContext, snapshot) {
if(snapshot.hasData) {
if(snapshot.data){
// Return your login here
return Container(color: Colors.blue);
}
// Return your home here
return Container(color: Colors.red);
} else {
// Return loading screen while reading preferences
return Center(child: CircularProgressIndicator());
}
},
));
}
I ran this code and it works fine. You should see a blue screen when login is required and a red screen when there's a user present. Uncomment the line in showLoginPage to test.
There is a much pretty way of doing this.
Assuming that you have some routes and a boolean SharedPreference key called initialized.
You need to use the WidgetsFlutterBinding.ensureInitialized() function before calling runApp() method.
void main() async {
var mapp;
var routes = <String, WidgetBuilder>{
'/initialize': (BuildContext context) => Initialize(),
'/register': (BuildContext context) => Register(),
'/home': (BuildContext context) => Home(),
};
print("Initializing.");
WidgetsFlutterBinding.ensureInitialized();
await SharedPreferencesClass.restore("initialized").then((value) {
if (value) {
mapp = MaterialApp(
debugShowCheckedModeBanner: false,
title: 'AppName',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: routes,
home: Home(),
);
} else {
mapp = MaterialApp(
debugShowCheckedModeBanner: false,
title: 'AppName',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: routes,
home: Initialize(),
);
}
});
print("Done.");
runApp(mapp);
}
The SharedPreference Class Code :
class SharedPreferencesClass {
static Future restore(String key) async {
final SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
return (sharedPrefs.get(key) ?? false);
}
static save(String key, dynamic value) async {
final SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
if (value is bool) {
sharedPrefs.setBool(key, value);
} else if (value is String) {
sharedPrefs.setString(key, value);
} else if (value is int) {
sharedPrefs.setInt(key, value);
} else if (value is double) {
sharedPrefs.setDouble(key, value);
} else if (value is List<String>) {
sharedPrefs.setStringList(key, value);
}
}
}

Resources