How to use websockets for my JSON streambuilder? - json

I have set up the streambuilder and stream async functions,but i do not know how to use it properly as it needs websockets. How can i use websockets in these case to fetch my Json data from my server?
Stream<List<Post>> FetchPosts(http.Client client) async* {
final response = await http.get("$SERVER_IP/api/articles/?format=json");
final parsed = jsonDecode(utf8.decode(response.bodyBytes)).cast<Map<String, dynamic>>();
yield parsed.map<Post>((json) => Post.fromJSON(json)).toList();
}
StreamBuilder<List<Post>>(
stream: FetchPosts(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData ? PostsList(posts: snapshot.data)
:
Center(child: CircularProgressIndicator(backgroundColor: Colors.pink,valueColor: new AlwaysStoppedAnimation<Color>(Colors.pinkAccent)));
},
),
Class
class Post {
final String id;
final String author;
final String caption;
Post({this.id, this.author,this.caption});
factory Post.fromJSON(Map<String, dynamic> jsonMapPost) {
return Post(
id: jsonMapPost['id'] as String,
caption: jsonMapPost['caption'] as String,
author: jsonMapPost['author'] as String,);}}
Json data
[{"id":"a4d64194-3d81-4a4e-b7e6-6fce36fea793","author":"a94d4433-ffaf-4af1-aa8d-67ac75bf2e53","caption":"this is caption",]}

You can use web_socket_channel package that provides StreamChannel wrappers for WebSocket connections.
With it you fetchPosts function can turn into something like that:
Stream<List<Post>> fetchPosts() {
final channel = IOWebSocketChannel.connect(Uri.parse("$SERVER_IP/api/articles/?format=json"));
return channel.stream.map((r) => parse(r));
}
If your websocket server emits message in this format:
[
{
"id": "a4d64194-3d81-4a4e-b7e6-6fce36fea793",
"author": "a94d4433-ffaf-4af1-aa8d-67ac75bf2e53",
"caption": "this is caption"
}
]
then your parse function can look like that:
List<Post> parse(String message) {
final json = jsonDecode(message) as List<dynamic>;
return json.map((j) => Post.fromJSON(j as Map<String, dynamic>)).toList();
}

Related

Json got parsed but the cannot display the data in the UI flutter

I was trying to fetch data results from a REST API and then display it in the UI. So everything went well the JSON was parsed well the try and catch method was working fine. But somehow the code was not able to display the parsed results in the UI. Neither gave me an error or exception. I have been struggling to attain the desired result for quite the past few days.
Model Class:
import 'dart:convert';
Transaction transactionFromJson(String str) =>
Transaction.fromJson(json.decode(str));
String transactionToJson(Transaction data) => json.encode(data.toJson());
class Transaction {
Transaction({
required this.dataDescription,
required this.orderStatus,
required this.statusObjects,
});
String dataDescription;
String orderStatus;
List<StatusObject> statusObjects;
factory Transaction.fromJson(Map<String, dynamic> json) => Transaction(
dataDescription: json["data-description"],
orderStatus: json["order-status"],
statusObjects: List<StatusObject>.from(
json["status-objects"].map((x) => StatusObject.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"data-description": dataDescription,
"order-status": orderStatus,
"status-objects":
List<dynamic>.from(statusObjects.map((x) => x.toJson())),
};
}
class StatusObject {
StatusObject({
required this.type,
required this.status,
required this.date,
required this.time,
});
String type;
String status;
DateTime date;
String time;
factory StatusObject.fromJson(Map<String, dynamic> json) => StatusObject(
type: json["type"],
status: json["status"],
date: DateTime.parse(json["date"]),
time: json["time"],
);
Map<String, dynamic> toJson() => {
"type": type,
"status": status,
"date": date.toIso8601String(),
"time": time,
};
}
This is how the JSON looks like:
{
"data-description": "This api will return an array of objects to be placed in the order status timeline on the second screen",
"order-status": "Success",
"status-objects": [
{
"type": "Payment",
"status": "completed",
"date": "2021-07-02T00:00:00",
"time": "12:00AM"
},
{
"type": "Units Allocated",
"status": "by Axis",
"date": "2021-07-13T00:00:00",
"time": "12:00AM"
}
]
}
API_Manager where the parsing and fetching took place Service Class
class API_Manager {
static Future<Transaction> getDetails() async {
var client = http.Client();
var transactions;
try {
var response = await client.get(
Uri.https("your api url here"));
if (response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = jsonDecode(jsonString);
transactions = Transaction.fromJson(jsonMap);
}
} catch (e) {
return transactions;
}
return transactions;
}
}
The UI component where I wanted to display the parsed JSON:
Code
FutureBuilder<Transaction>(
future: API_Manager.getDetails(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var data = snapshot.data!.statusObjects;
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) =>
Text('$index : ${data[index].status}'),
);
}
return Text('Something was wrong!');
},
),
The output that I am getting is "Something was wrong"
I am quite sure that I have been missing a very small piece of code to make it work. I have been working on this piece of code for quite a few days but am unable to do it. I request you, people, to please help me out in attaining the result or point out the piece of code that I have left out.
Will appreciate it if you could help me in any possible way.
try this
var response = await client
.get(Uri.https("domain", "accounts/test-data/"));
or
var response = await http
.get(Uri.parse("domain/accounts/test-data/"));
This one doesn't work maybe because of the main domain part shouldn't use /, because it indicates subPath,
var response = await client
.get(Uri.https("domain/accounts", "test-data/"));

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.

How to convert data from json to List<Object> in Flutter

I need to obtain a list of Articles(a custom object) from a realtime database in Firebase. I first decode my data from a json data type. Then I try to convert it into a list using this line of code:
List<Article> articles = List<Article>.from(articleResponse)
.map((Map model) => Article.fromJson(model))
.toList();
However, this gives a syntax error of "The argument type 'Article Function(Map<dynamic,dynamic>)' can't be assigned to the parameter type 'dynamic Function(Article)'." I have included the code I use to fetch an Article(the custom object) as well as the factory method for the class.
//Method to get articles
Future<List<Article>> fetchArticles() async {
final response = await http.get(
"https://some-server.firebaseio.com/some-url.json");
final articleResponse = json.decode(response.body);
List<Article> articles = List<Article>.from(articleResponse)
.map((Map model) => Article.fromJson(model))
.toList(); // Now we're looping over the response entries (maps of article info) to create Article instances
return articles;
}
\\Factory Method
factory Article.fromJson(Map<String, dynamic> json) {
return Article(
id: json['id'],
title: json['title'],
author: json['author'],
date: json['date'],
imageUrl: json['imageUrl'],
modalities: json['modalities'],
);
}
I make an example with something like a json response.
void main() {
//this is an example like a json response
List<Map<String, dynamic>> articleResponse = [
{
"id":"1",
"name":"test1"
},
{
"id":"2",
"name":"test2"
}
];
List<Article> articles = List<Article>.from(articleResponse.map((Map art)=>Article.fromJson(art)))
.toList();
print('${articles.length} articles in the list!! use to render de ui list');
}
class Article{
String id;
String name;
Article({this.id,this.name});
factory Article.fromJson(Map<String, dynamic> json) {
return Article(
id: json['id'],
name: json['name'],
);
}
}
basically you need to change your method to get articles with this.
//Method to get articles
Future<List<Article>> fetchArticles() async {
final response = await http.get(
"https://some-server.firebaseio.com/some-url.json");
final articleResponse = json.decode(response.body);
List<Article> articles = List<Article>.from(articleResponse.map((Map art)=>Article.fromJson(art)))
.toList(); // Now we're looping over the response entries (maps of article info) to create Article instances
return articles;
}
you can use JsonToDart
this is create a class for parse your complex json data
paste json and get class of model
you can overrride toString in your model like:
#override
String toString() {
return '{
id: $id,
title: $title,
author: $author,
date: $date,
imageUrl: $imageUrl,
modalities: $modalities
}';
}
and override toMap :
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'title': title,
'author': author,
'date': date,
'imageUrl': imageUrl,
'modalities': modalities,
};
}
and you can use serialization that. this can help you

Adding data to a json file in dart

I have a Json file having some user data as an array , I am able to read those data in my flutter project , But what I wanna do is to add some other user from the data I receive from the textfield in my flutter app.
Can anyone tell me how to do that ? Thanks in advance.
My Json file looks something like this.
{
"users": [
{
"id": 1,
"username": "steve",
"password": "captainamerica"
}
]
}
and I have to add another user with id - 2, username - tony, and password - ironman.
I have tried showing you how to map the JSON to OBJECT and then add a new user to the users object and then to JSON again.
Here's the complete code:
If you have any doubts, please ask:
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
UsersPodo _usersPodo; // Users object to store users from json
// A function that converts a response body into a UsersPodo
UsersPodo parseJson(String responseBody) {
final parsed = json.decode(responseBody);
return UsersPodo.fromJson(parsed);
}
class Demo extends StatefulWidget {
#override
_Demo createState() => _Demo();
}
class _Demo extends State<Demo> {
final String localJson = '''
{
"users": [
{
"id": 1,
"username": "steve",
"password": "captainamerica"
}
]
}'''; // local json string
Future<UsersPodo> fetchJSON() async {
return compute(parseJson, localJson);
}
Widget body() {
return FutureBuilder<UsersPodo>(
future: fetchJSON(),
builder: (context, snapshot) {
return snapshot.hasError
? Center(child: Text(snapshot.error.toString()))
: snapshot.hasData
? _buildBody(usersList: snapshot.data)
: Center(child: Text("Loading"));
},
);
}
Widget _buildBody({UsersPodo usersList}) {
_usersPodo = usersList;
_usersPodo.users.add(new Users(id: 1, username: "omishah", password: "somepassword")); // add new user to users array
return Text(_usersPodo.users[1].toJson().toString()); // just for the demo output
// use _usersPodo.toJson() to convert the users object to json
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xfff3f3f3),
appBar: AppBar(backgroundColor: Colors.red[900], title: Text("DEMO")),
body: body());
}
}
// PODO Object class for the JSON mapping
class UsersPodo {
List<Users> users;
UsersPodo({this.users});
UsersPodo.fromJson(Map<String, dynamic> json) {
if (json['users'] != null) {
users = new List<Users>();
json['users'].forEach((v) {
users.add(new Users.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.users != null) {
data['users'] = this.users.map((v) => v.toJson()).toList();
}
return data;
}
}
class Users {
int id;
String username;
String password;
Users({this.id, this.username, this.password});
Users.fromJson(Map<String, dynamic> json) {
id = json['id'];
username = json['username'];
password = json['password'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['username'] = this.username;
data['password'] = this.password;
return data;
}
}

Flutter and Distance Matrix API parsing json

I am currently building a flutter app where I want to calculate the distance between some objects and am using the Google Distance Matrix API to do so. I am having trouble parsing the json using Dart. All I want ultimately is a list of the distances from the json results so that I can index them and apply them to the data in my app.
The json results look like this:
{
"destination_addresses" : [
"destination address",
"destination address"
],
"origin_addresses" : [ "Origin addresses here" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "4.3 mi",
"value" : 6998
},
"duration" : {
"text" : "14 mins",
"value" : 848
},
"status" : "OK"
},
{
"distance" : {
"text" : "6.7 mi",
"value" : 10728
},
"duration" : {
"text" : "22 mins",
"value" : 1327
},
"status" : "OK"
}
]
}
],
"status" : "OK"
}
I ultimately would like to end up with a list (in dart) that is just a list of the distance "text" values within the elements array but I am having trouble getting this to return. I have tried creating a class and mapping the json results to this but unsuccesfully as I am not very good at parsing json so any advice on how to end up with this list would be gratefully received!
I have tried this code to parse the json but am really struggling to make it work and then apply it:
class Topleveladd {
final String elements;
Topleveladd({this.elements});
factory Topleveladd.fromJson(Map<String, dynamic> parsedJson) {
return Topleveladd(elements: parsedJson['rows']);
}
}
class Elements {
List<Distance> distanceslist;
Elements({this.distanceslist});
factory Elements.fromJson(Map<String, dynamic> parsedJson) {
var list = parsedJson['elements'] as List;
print(list.runtimeType); //returns List<dynamic>
List<Distance> distancesList =
list.map((i) => Distance.fromJson(i)).toList();
return Elements(distanceslist: distancesList);
}
}
class Distance {
String text;
Distance({this.text});
factory Distance.fromJson(Map<String, dynamic> parsedJson) {
return new Distance(
text: parsedJson['distance'],
);
}
}
Okay this is it working with me accessing the JSON you've given as an asset so you'll probably have to change the loadData method for it to fit your needs.
DistanceMatrix class:
import 'dart:convert';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
class DistanceMatrix {
final List<String> destinations;
final List<String> origins;
final List<Element> elements;
final String status;
DistanceMatrix({this.destinations, this.origins, this.elements, this.status});
factory DistanceMatrix.fromJson(Map<String, dynamic> json) {
var destinationsJson = json['destination_addresses'];
var originsJson = json['origin_addresses'];
var rowsJson = json['rows'][0]['elements'] as List;
return DistanceMatrix(
destinations: destinationsJson.cast<String>(),
origins: originsJson.cast<String>(),
elements: rowsJson.map((i) => new Element.fromJson(i)).toList(),
status: json['status']);
}
static Future<DistanceMatrix> loadData() async {
DistanceMatrix distanceMatrix;
try{
String jsonData = await rootBundle.loadString('assets/data.json');
distanceMatrix = new DistanceMatrix.fromJson(json.decode(jsonData));
} catch (e){
print(e);
}
return distanceMatrix;
}
}
class Element {
final Distance distance;
final Duration duration;
final String status;
Element({this.distance, this.duration, this.status});
factory Element.fromJson(Map<String, dynamic> json) {
return Element(
distance: new Distance.fromJson(json['distance']),
duration: new Duration.fromJson(json['duration']),
status: json['status']);
}
}
class Distance {
final String text;
final int value;
Distance({this.text, this.value});
factory Distance.fromJson(Map<String, dynamic> json) {
return new Distance(text: json['text'], value: json['value']);
}
}
class Duration {
final String text;
final int value;
Duration({this.text, this.value});
factory Duration.fromJson(Map<String, dynamic> json) {
return new Duration(text: json['text'], value: json['value']);
}
}
Main.dart which uses ListView.builder to display the distances text and values as a ListTile:
import 'package:flutter/material.dart';
import 'package:hello_world/distance_matrix.dart';
void main() async {
runApp(new MyApp(
distanceMatrix: await DistanceMatrix.loadData(),
));
}
class MyApp extends StatefulWidget {
final DistanceMatrix distanceMatrix;
#override
_MyAppState createState() => new _MyAppState();
MyApp({this.distanceMatrix});
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Material(
child: ListView.builder(
itemCount: widget.distanceMatrix.elements.length,
itemBuilder: (context, index){
return ListTile(
title: Text(widget.distanceMatrix.elements[index].distance.text),
subtitle: Text(widget.distanceMatrix.elements[index].distance.value.toString()),
);
},
)
)));
}
}
Image to show what you should get: