I seriously need assistance. I want to show API data on a listview, but It is not showing, only showing circular progress dialog. My api function is working well as it is printing valid json data on console. When I show and navigate to ResultsPage, It just shows circular progress dialog and not the data. Can you tell me where am I going wrong, why the data is not displaying
Your help will be appreciated.
My API function
Future<List<Autogenerated>?> signInData() async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('token');
try {
Response response = await _dio.post('$_baseUrl/api/gateway',
data: {
"ClientPackageId": "0cdd231a-d7ad-4a68-a934-d373affb5100",
"PlatformId": "ios",
"ClientUserId": "AhmedOmar",
"VinNumber": VINumber
},
options: Options(
headers: {
"Content-Type": "application/json;charset=UTF-8",
"Charset": 'utf-8',
"Authorization": "Bearer $token",
},
));
print("data is here");
print(json.encode(response.data));
print(response.statusCode);
if (response.statusCode == 200) {
print("decoded");
List<Map<String, dynamic>> map = [];
map = List<Map<String, dynamic>>.from(
jsonDecode(json.encode(response.data)));
print(map);
// return List<Autogenerated>.from(
// response.data.map((i) => Autogenerated.fromJson(i)));
// return Autogenerated.fromJson(jsonDecode(json.encode(response.data)));
} else if (response.statusCode == 500) {
// call your refresh token api here and save it in shared preference
print(response.statusCode);
await getToken();
signInData();
} else {
throw Exception('Failed to load data');
}
} catch (e) {
print(e);
}
// return null;
}
Where I want to show the list
class ResultsPage extends StatefulWidget {
const ResultsPage({Key? key}) : super(key: key);
#override
_ResultsPageState createState() => _ResultsPageState();
}
class _ResultsPageState extends State<ResultsPage> {
Future<List<Autogenerated>?>? objectList;
_APIState? api;
#override
void initState() {
super.initState();
objectList = api?.signInData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
//centerTitle: true,
),
body: Center(
child: FutureBuilder<List<Autogenerated>?>(
future: objectList,
builder: (context, snapshot) {
if (snapshot.hasData) {
print("snapshot data:");
print(snapshot.hasData);
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: (context, index) {
var title = snapshot.data?[index].category;
// var company = snapshot.data[index]['company_name'];
// var skills = snapshot.data[index]['skills'];
// var description = snapshot.data[index]['description'];
// var positions = snapshot.data[index]['positions'];
return Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.green.shade300,
),
borderRadius: BorderRadius.circular(15.0),
),
child: ListTile(
leading: Text(title!),
title: Text(title),
subtitle: Text(
title + '\n' + title,
),
trailing: Text(title),
),
);
},
));
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
));
}
}
You need to open the comment and return.
Future<List<Autogenerated>?> signInData() async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('token');
try {
Response response = await _dio.post('$_baseUrl/api/gateway',
data: {
"ClientPackageId": "0cdd231a-d7ad-4a68-a934-d373affb5100",
"PlatformId": "ios",
"ClientUserId": "AhmedOmar",
"VinNumber": VINumber
},
options: Options(
headers: {
"Content-Type": "application/json;charset=UTF-8",
"Charset": 'utf-8',
"Authorization": "Bearer $token",
},
));
print("data is here");
print(json.encode(response.data));
print(response.statusCode);
if (response.statusCode == 200) {
print("decoded");
List<Map<String, dynamic>> map = [];
map = List<Map<String, dynamic>>.from(
jsonDecode(json.encode(response.data)));
print(map);
// return List<Autogenerated>.from(
// response.data.map((i) => Autogenerated.fromJson(i)));
// return Autogenerated.fromJson(jsonDecode(json.encode(response.data)));
} else if (response.statusCode == 500) {
// call your refresh token api here and save it in shared preference
print(response.statusCode);
await getToken();
signInData();
} else {
throw Exception('Failed to load data');
}
} catch (e) {
print(e);
}
// return null;
}```
Related
I am fetching the user data through the fetchUser() method on the home screen but when I update the income, it is not updated on the home screen when I navigate back. How can I make the method fetchUser be called each time I navigate to the home screen?
Or what else I can do so I can achieve this?
import 'dart:async';
import 'dart:convert';
import 'package:fin_app/apiservice/variables.dart';
import 'package:month_year_picker/month_year_picker.dart';
// import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:fin_app/screens/login_screen/components/overview_screen/top_card.dart';
import 'package:flutter/material.dart';
import '../../models/user.dart';
import '../monthly_expense/expense_app_theme.dart';
import 'input_form.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String dropdownValue = list.first;
List userData = [];
#override
void initState() {
super.initState();
fetchUser();
}
Future<User> fetchUser() async {
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
final response = await http.get(
Uri.parse('https://10.0.2.2:7014/api/user/me'),
headers: requestHeaders,
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
// income=jsonDecode(response.body)['income'];
income=jsonDecode(response.body)['profile']['income'];
return User.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
print(response.statusCode.toString());
throw Exception('Failed to load user');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ExpenseAppTheme.background,
body: Column(
children: [
SizedBox(height: 15),
TopNeuCard(balance: '\ 20,000', expense: '100'),
Expanded(
child: Container(
child: Center(
child: Column(
children: [
Container(
padding: EdgeInsets.only(left: 30.00),
alignment: Alignment.topLeft,
child: DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 100,
style: const TextStyle(
color: Color.fromARGB(255, 44, 121, 244)),
underline: Container(
height: 2,
color: Color.fromARGB(255, 44, 121, 244),
),
onChanged: (String? value) {
// This is called when the user selects an item.
setState(() {
dropdownValue = value!;
});
_fetchData();
},
items: list.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
Container(height: 275, child: _buildListView(context))
],
)),
)),
],
),
floatingActionButton: FloatingActionButton(
onPressed: navigate,
backgroundColor: Color.fromARGB(255, 121, 146, 237),
child: const Icon(Icons.add_rounded),
),
);
}
Future<void> _fetchData() async {
var apiUrl2 =
'https://10.0.2.2:7014/api/expense/me/month?month=2022%20$dropdownValue';
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
final response = await http.get(
Uri.parse(apiUrl2),
headers: requestHeaders,
);
final data = json.decode(response.body);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
setState(() {
userData = data;
});
} else if (response.statusCode == 404) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("No expenses present")));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
print(response.statusCode.toString());
throw Exception('Failed to load expenses');
}
}
Future deletePost(String id) async {
var apiUrl = 'https://10.0.2.2:7014/api/expense/me/$id';
// final res = await http.delete(Uri.parse(apiUrl));
// if (res.statusCode == 200) {
// print("Deleted");
// } else {
// throw "Sorry! Unable to delete this post.";
// }
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
final response = await http.delete(
Uri.parse(apiUrl),
headers: requestHeaders,
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Deleted succesfully")));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
print(response.statusCode.toString());
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Expense could not be deleted ")));
throw Exception('Failed to load expenses');
}
}
void navigate() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const FormInput()),
);
}
ListView _buildListView(BuildContext context) {
return ListView.builder(
itemCount: userData.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(userData[index]["category"]),
subtitle: Text(userData[index]["date"]),
leading: IconButton(
icon: Icon(Icons.delete),
color: Colors.red,
onPressed: () {
setState(() {
deletePost(userData[index]["id"]);
userData.removeAt(index);
});
},
),
trailing: Text(
'-' '\$' + userData[index]["amount"].toString(),
style: TextStyle(
//fontWeight: FontWeight.bold,
fontSize: 16,
color: Colors.red,
),
),
onTap: () {},
));
},
);
}
}
Change this:
void navigate() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const FormInput()),
);
}
to this:
void navigate() async {
bool result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const FormInput()),
);
if(result != null && result){
fetchUser();
}
}
then inside FormInput, pop like this:
Navigator.pop(context, true);
I've been learning for days about him. But I still can't display it on screen. Maybe anyone can help ? please check it. i want to get some user data on my screen with Dio Package
in this dio client i try tu generalize every request in 1 .dart
Dio_Client.dart
import 'package:dio/dio.dart';
import 'package:latihan_dio/dio_interceptor.dart';
import '../../../../dio_client.dart';
import '/src/features/home/domain/user.dart';
enum RequestType { GET, POST, PUT, PATCH, DELETE }
class DioClient {
final dio = createDio();
DioClient._internal();
static final _singleton = DioClient._internal();
factory DioClient() => _singleton;
static Dio createDio() {
var dio = Dio(BaseOptions(
baseUrl: "https://reqres.in/api/users?page=2",
receiveTimeout: 20000, // 20 seconds
connectTimeout: 20000,
sendTimeout: 20000,
));
// dio.interceptors.addAll({
// AuthInterceptor(dio),
// });
// dio.interceptors.addAll({
// Logging(dio),
// });
return dio;
}
Future<Response<dynamic>> apiCall({
required String url,
required RequestType requestType,
Map<String, dynamic>? queryParameters,
Map<String, dynamic>? body,
Map<String, String>? header,
RequestOptions? requestOptions,
}) async {
late Response result;
// try {
switch (requestType) {
case RequestType.GET:
{
Options options = Options(headers: header);
result = await dio.get(url,
queryParameters: queryParameters, options: options);
break;
}
case RequestType.POST:
{
Options options = Options(headers: header);
result = await dio.post(url, data: body, options: options);
break;
}
case RequestType.DELETE:
{
Options options = Options(headers: header);
result =
await dio.delete(url, data: queryParameters, options: options);
break;
}
case RequestType.PUT:
{
Options options = Options(headers: header);
result = await dio.put(url, data: body, options: options);
break;
}
case RequestType.PATCH:
{
Options options = Options(headers: header);
result = await dio.patch(url, data: body, options: options);
break;
}
}
return result;
// if(result != null) {
// // return NetworkResponse.success(result.data);
// // } else {
// // return const NetworkResponse.error("Data is null");
// // }
// // }on DioError catch (error) {
// // return NetworkResponse.error(error.message);
// // } catch (error) {
// // return NetworkResponse.error(error.toString());
}
}
// }**
in this home screen i try to call api wit fetch user
home_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:latihan_dio/src/features/home/domain/user.dart';
import '../../../../dio_client.dart';
class myHomepage extends StatefulWidget {
const myHomepage({Key? key}) : super(key: key);
#override
State<myHomepage> createState() => _myHomepageState();
}
class _myHomepageState extends State<myHomepage> {
List<User> users = [];
var selectedIndex = 0;
#override
void initState() {
super.initState();
fetchData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
child: Column(
children: [
ListView.builder(
// padding: EdgeInsets.symmetric(vertical: 16.5),
// scrollDirection: Axis.horizontal,
itemCount: users.length,
itemBuilder: (context, index) {
return Center(
child: Center(
child: Text(
'[data]${users[index]}',
style: TextStyle(
fontSize: 100,
color: Colors.red,
),
)),
);
},
),
// Text('data2'),
// Text('data3'),
// Text('data4'),
],
),
),
TextButton(
onPressed: () {},
child: Text(
'GET',
style: TextStyle(
fontSize: 100,
),
),
),
],
),
);
}
}
Future<void> fetchData() async {
var Response = await DioClient().apiCall(
url: 'https://reqres.in/api/users?page=2',
requestType: RequestType.GET,
// queryParameters: {},
);
List<dynamic> listUser = Response.data['result'];
List<User> users = listUser.map((e) => User.fromJson(e)).toList();
}
user.dart iam using freezed package for models,
// To parse this JSON data, do
//
// final user = userFromMap(jsonString);
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:convert';
part 'user.freezed.dart';
part 'user.g.dart';
#freezed
abstract class User with _$User {
const factory User({
#JsonKey(name: 'id') int? id,
#JsonKey(name: 'email') String? email,
#JsonKey(name: 'first_name') String? firstName,
#JsonKey(name: 'last_name') String? lastName,
#JsonKey(name: 'avatar') String? avatar,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
Instead of call async in initState, use FutureBuilder and you not checking the response to be success and also your get your list by calling Response.data['result'] instead of Response.data['data'] .Do like this:
Future<List<User?>> fetchData() async {
var Response = await DioClient().apiCall(
url: 'https://reqres.in/api/users?page=2',
requestType: RequestType.GET,
// queryParameters: {},
);
if (Response.statusCode == 200) {
List<dynamic> listUser = Response.data['data'];
List<User> users = listUser.map((e) => User.fromJson(e)).toList();
return users;
} else {
return [];
}
}
then use it like this:
Center(
child: FutureBuilder<List<User?>>(
future: fetchData(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<User?> data = snapshot.data ?? [];
return ListView.builder(
itemBuilder: (context, index) {
return Column(children: [
Text(data[index]?.firstName?? ''),
]);
},
itemCount: data.length,
);
}
}
},
),
)
try this
Future<void> fetchData() async {
var Response = await DioClient().apiCall(
url: 'https://reqres.in/api/users?page=2',
requestType: RequestType.GET,
// queryParameters: {},
);
List<dynamic> listUser = Response.data['result'];
users = listUser.map((e) => User.fromJson(e)).toList();
}
//remove reinit of userslist
Future<void> fetchData() async {
var Response = await DioClient().apiCall(
url: 'https://reqres.in/api/users?page=2',
requestType: RequestType.GET,
// queryParameters: {},
);
List<dynamic> listUser = Response.data;
// OR
List<dynamic> listUser = Response.data['data]; // if you want to acces s data inside it
List<User> users = listUser.map((e) => User.fromJson(e)).toList();
}
Try this
In this code, I cache data from Firebase realtime data base and then save it locally in Hive database. All this code used to work in another project that was null safe, but implementing this in an old project does not work. Where is the problem?
Here is the code:
class NewHomeScreen extends StatefulWidget {
const NewHomeScreen({Key key}) : super(key: key);
#override
_NewHomeScreenState createState() => _NewHomeScreenState();
}
class _NewHomeScreenState extends State<NewHomeScreen> {
List stories = [];
Box<Story> storyBox;
List<String> keys;
#override
void initState() {
super.initState();
}
Future openBox() async {
final document = await getApplicationDocumentsDirectory();
Hive.init(document.path);
Hive.registerAdapter<Story>(StoryAdapter());
storyBox = await Hive.openBox<Story>('storyBoxName');
print('Box Opened!');
}
Future<bool> getAllData() async {
const url = 'https://shaparak-732ff.firebaseio.com/items.json';
await openBox();
try {
final response = await http.get(Uri.parse(url));
final extractedData = json.decode(response.body) as Map<String, dynamic>;
await putData(extractedData);
} catch (SocketException) {
print('No Internet');
}
var mymap = storyBox.toMap().values.toList();
if (mymap.isEmpty) {
stories.add('empty');
} else {
stories = mymap;
}
return Future.value(true);
}
Future putData(Map<String, dynamic> data) async {
await storyBox.clear();
Story newStory;
data.forEach((key, value) {
newStory = Story(
author: value['author'],
category: value['category'],
content: value['content'],
id: key.toString(),
title: value['title'],
);
storyBox.put(key, newStory);
});
}
Future<void> updateData() async {
const url = 'https://shaparak-732ff.firebaseio.com/items.json';
try {
final response = await http.get(Uri.parse(url));
final extractedData = json.decode(response.body) as Map<String, dynamic>;
await putData(extractedData);
setState(() {});
} catch (SocketException) {
Fluttertoast.showToast(
msg: "This is Center Short Toast",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
print('No Internet');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFFDEBF7),
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColor,
title: Text("Shaparak"),
),
body: Center(
child: FutureBuilder(
future: getAllData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (stories.isEmpty) {
return const Text(
'No Data',
style: TextStyle(
fontSize: 24.0,
),
);
} else {
return RefreshIndicator(
onRefresh: updateData,
child: ItemsGrid(storyBox.toMap().values.toList()),
);
}
} else {
return const CircularProgressIndicator();
}
},
),
),
);
}
}
This used to work in a null safety migrated project, but implementing this in an old project which is not null safe, does not work. Can you please guide me how to solve it?
It looks like you need to add the getAllData() to the initState function.
Hmm. May be it is the issue with the dart SDK version.
This print('response>>>>>>'); print(response); is NULL
print ("api") - this return is OK
In Api.dart
Future list(arguments) async {Dio dio = new Dio();
try {
var arg = arguments;
String refreshToken = token;
dio.options.baseUrl = serverUrl + "/test/" + arg.toString();
dio.options.responseType = ResponseType.json;
Response response = await dio.get(
"${dio.options.baseUrl}",
options: Options(
headers: {
'Authorization': "Bearer $refreshToken",
'Content-Type': "application/json;charset=UTF-8",
'Accept': "gzip"
}
)
);
print ("api");
print(response.data);
return await response.data;
} catch (e) {
print(e);
}
myclass.dart
cl
ass Page extends StatefulWidget {
#override
PageState createState() => PageState();
}
class PageState extends State<Page> {
List data;
Future<List> list() async {
Network network = new Network();
final String arguments = ModalRoute.of(context).settings.arguments as String;
print(arguments);
var response = await network.list(arguments.toString());
print('response>>>>>>');
print(response);
if (mounted){
this.setState(() {
data = response;
});
};
// _saving = false;
// print('data');
// print(data);
// return "Success!";
}
#override
void initState(){
super.initState();
// Future.delayed(Duration.zero, this.dados_propostas);
// dados_propostas();
}
#override
Widget build(BuildContext context) {
this.list();
return AlertDialog(
title: const Text('Teste'),
actions: <Widget>[
FlatButton(
onPressed: debugDumpApp,
child: Row(
children: <Widget>[
const Icon(
Icons.dvr,
size: 18.0,
),
Container(
width: 8.0,
),
const Text('DUMP'),
],
),
),
FlatButton(
onPressed: () {
Navigator.pop(context, false);
},
child: const Text('OK'),
),
],
);
}
}
Use this function:
Future<Response> get(String url, String token) async {
Response response = Response();
try {
dio.options.contentType = "application/json;charset=UTF-8";
dio.options.headers["Authorization"] = "Bearer $token";
response = await dio.get(url);
return response;
} on DioError catch (error, stacktrace) {
print("Exception occured: $error stackTrace: $stacktrace");
return error.response;
}
}
EDIT:
Since the data is now showing if I do hot reload after the error. I am assuming that my other Futurethat isn't included in my FutureBuilder triggers that error.
HERE ARE THE ACTUAL FUNCTIONS:
List<Feed> feedList = [];
List<User> userList = [];
#override
void initState() {
super.initState();
getFeed = getFeedAll();
this.getUsers();
}
Future<List<Feed>> getFeedAll() async {
var res = await http.get(
Uri.encodeFull(APIServices.httpDomain + APIServices.postGetAll),
headers: {"Authorization": "Bearer " + Constants.token});
if (res.statusCode == 200) {
var data = json.decode(res.body);
this.getUsers();
feedList = data.map<Feed>((json) => Feed.fromJson(json)).toList();
}
return feedList;
}
Future<List<User>> getUsers() async {
var res = await http.get(
Uri.encodeFull(APIServices.httpDomain + APIServices.usersAll),
headers: {"Authorization": "Bearer " + Constants.token});
if (res.statusCode == 200) {
var data = json.decode(res.body);
userList = data.map<User>((json) => User.fromJson(json)).toList();
}
return userList;
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: getFeed,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
padding: EdgeInsets.all(10),
child: feedListWidget(snapshot.data));
} else {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: Container(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
),
);
}
},
);
}
Now, I am using userList inside my feedListWidget widget.
I am pretty sure that getUsers() triggers that error.
How can I include getUsers() inside my FutureBuilder?
Because that's what I think will solve my problem.
Seems like you are not waiting for the data here:
getFeed = getFeedAll();
this.getUsers();
Use await to perform that
getFeed = await getFeedAll();
await this.getUsers();