Flutter: FutureBuilder How can I load a future that receives arguments? - flutter

I am working with a FutureBuider and I don't know how I can load a Future that receives an argument. I get an error, the future is in an external file 'provider.dart', I attach an image of the error:
1 positional argument(s) expected, but 0 found.
Try adding the missing arguments.dart(not_enough_positional_arguments)
To explain myself better I have to mention the structure of the application:
HomePage: in it you select an image that will be sent to a 'provider.dart' file.
PhotoPage: On this page, a value obtained from the Provider.dart file is obtained through a FutureBuilder, as shown in the image above.
children: [
FutureBuilder(
future: fotoProvider.uploadImageCloudinary(),
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text('ERROR: ${snapshot.error.toString()}'),
);
}
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return Center(
// I WOULD LIKE TO PRESENT THE RESULTS OF THE SECOND FUTURE HERE
child: Text(snapshot.data),
);
},
),
],
),
Provider.dart: There are two Future's:
1 Future: It receives the image from the home and processes it sending it to the Cloudinary API, I get the url generated by Cloudinary to be sent to the second Future.
Future<String> uploadImageCloudinary(File imagen) async {
final url = Uri.parse('https://api.cloudinary.com/...');
final mimeType = mime(imagen.path).split('/'); // Image/jpeg
final imageUploadRequest = http.MultipartRequest('POST', url);
final file = await http.MultipartFile.fromPath(
'file',
imagen.path,
contentType: MediaType(mimeType[0], mimeType[1]),
);
imageUploadRequest.files.add(file);
// execute request
final streamResponse = await imageUploadRequest.send();
final resp = await http.Response.fromStream(streamResponse);
if (resp.statusCode != 200 && resp.statusCode != 201) {
print('Something went wrong');
print(resp.body); // Error
return null;
}
dynamic respData = json.decode(resp.body);
print(respData);
urlGenCloudinary = respData['secure_url'];
// Shipment to the second future
return await requestSecondAPI(urlGenCloudinary);
}
2 Future: It receives the url and sends it to another API, this one processes it and generates a String that is the data that I want to be sent to FutureBuilder in FotoPage.
Future requestSecondAPI(String url) async {
final String apiUrl =
"https://api...";
final res = await http.post(
Uri.parse(apiUrl),
headers: {
"Content-type": "application/json",
"Authorization": "Key "
},
body: jsonEncode({
"inputs": [
{
"data": {
"image": {'url': url}
}
}
],
"model": {
"output_info": {
"output_config": {"max_concepts": 40, "min_value": 0.8}
}
}
}),
);
final resReqRes = reqResRespuestaFromJson(res.body);
String resultado = resReqRes.outputs[0].data.concepts[0].id;
return resultado;
}
Thank you in advance.
I tried to place the second Future in the FutureBuilder and I get the following errors:
In FutureBuilder:
"Couldn't infer type parameter 'T'. "
In the future within the FutureBuilder:
"1 positional argument(s) expected, but 0 found.
Try adding the missing arguments."
In the builder:
"The argument type 'Center Function(BuildContext, AsyncSnapshot)' can't be assigned to the parameter type 'Widget Function(BuildContext, AsyncSnapshot)' "

Related

How to extract values from onCall firebase function and load them in future builder

i have a onCall cloud function which is returning
resp.status(200).send(JSON.stringify(entities));
In my flutter app, i have created this future to get values from it.
Future<void> dataDriven(String filename) async {
HttpsCallable callable =
FirebaseFunctions.instance.httpsCallable('fruitsType');
final results = await callable;
final datE = results.call(<String, dynamic>{
'filename': 'filename',
});
final dataF = await datE.then((value) => value.data);
print (dataF);
}
It is successfully printing the response which is as per expectation. but my snapshot is always returning null. It is not even reaching hasData stage. Please help.
Response;
[{"name":"banana","type":"fruit","count":0,"color":"yellow"},{{"name":"apple","type":"fruit","count":2,"color":"red"}]
FutureBuilder(
future: dataDriven('fruits.txt'),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: Text('An error has occurred!'),
);
} else {
final data = snapshot.data;
return Text(data.toString());
}
It looks like there are some issues that need to be fixed (See comments in code).
// Set the correct return type (not void because you are returning data)
Future<String> dataDriven(String filename) async {
HttpsCallable callable = FirebaseFunctions.instance.httpsCallable('fruitsType');
// You can just call the function here with await
final result = await callable.call({
// Remove the quotes on the filename value
'filename': filename,
});
// Don't forget to return the data
return result;
}
I suggest reading up on the documentation about calling cloud functions from a flutter app and basic dart syntax.

Flutter Multiple functions in a FutureBuilder

In a Future Builder im trying to use two methods with different types, both of them fetch data from the api,
the main problem that im having is that both of the function have different types, so im having problem on putting
the two methods because of their types. I tried using
Future.wait(Future[]) aswell but i was getting many errors, there errors where mostly on List,
im still trying to learn how Future Builders work, i worked with FutureBuilders before but didnt have to use two functions inside the FutureBuilder. So if anyone could implement their solution on my code, that would really help and maybe add some comments on why did you make the change so i learn for the future. As a bonus im getting the List is not a subtype of type Map<String, dynamic> error aswell so if anyone could help with that too it would be very helpful. Tried looking into stack over flow answers for that but i couldnt figure it out since i was getting an error on this part
buildSwipeButton() {
return MenuPage(
sendData: fetchLoginData()// i was getting error here,
);
}
buildSwipeButton() {
return MenuPage( // other class name from a different file
sendData: fetchLoginData(),
);
}
buildSwipeButton2() {
return MenuPage( // other class name from a different file
sendData2: fetchWorkingLocationData(),
);
}
Future<LoginData>? fetchLoginData() async {
var url = 'https://dev.api.wurk.skyver.co/api/employees';
String basicAuth = 'Basic ' +
base64Encode(
utf8.encode('${emailController.text}:${passwordController.text}'),
);
var response = await http.get(
Uri.parse(url),
headers: <String, String>{'authorization': basicAuth},
);
print(response.body);
if (response.statusCode == 200) {
print(response.statusCode);
return LoginData.fromJson(
jsonDecode(response.body),
);
} else {
throw Exception('Failed to load LoginData');
}
}
Future<WorkingLocationData>? fetchWorkingLocationData() async {
var url = 'https://dev.api.wurk.skyver.co/api/locations';
String basicAuth = 'Basic ' +
base64Encode(
utf8.encode('${emailController.text}:${passwordController.text}'),
);
var response2 = await http.get(
Uri.parse(url),
headers: <String, String>{'authorization': basicAuth},
);
print(response2.body);
if (response2.statusCode == 200) {
print(response2.statusCode);
return WorkingLocationData.fromJson(
jsonDecode(response2.body),
);
} else {
throw Exception('Failed to load Working Location Data');
}
}
// other file where im trying to use Future Builder
late LoginData data;
Future<LoginData>? sendData;
Future<WorkingLocationData>? sendData2;
body: FutureBuilder<LoginData>(
future: sendData, // trying to use sendData and sendData2
builder: (context, snapshot) {
if (snapshot.hasData) {
LoginData? data1 = snapshot.data;
data = data1!;
print(data.loginPhoneNumber);
return afterLoginBody();
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return Center(child: const CircularProgressIndicator());
},
),
),
Try below code hope its help to you.
late LoginData data;
Future<LoginData>? sendData;
Future<WorkingLocationData>? sendData2;
body: FutureBuilder<LoginData>(
Future.wait([sendData, sendData2]),
builder: (context, AsyncSnapshot<List<dynamic>> snapshot{
snapshot.data[0]; //sendData
snapshot.data[1]; //sendData2
},
),
),
You can try this:
Future? _future;
Future<dynamic> sendData() async {
final data1 = await sendData1();
final data2 = await sendData2();
return [data1, data2];
}
#override
void initState() {
_future = sendData()();
super.initState();
}
///
FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CupertinoActivityIndicator();
}
if (snapshot.hasError) {
return SomethingWentWrong();
}
final data1= snapshot.data[0] as YourDataModel;
final data2 = snapshot.data[1] as YourDataModel;
});

Flutter rest api all my data is showing null

I am learning to use api and all data in my interface is showing as null
in this section to understand where the problem lies i change ! with ?
How can I check if there is a problem while pulling the data?
I deleted the irrelevant parts to shorten the code.
WeatherApiClient client = WeatherApiClient();
Hava? data;
Future<void> getData()async{
data = await client.getCurrentWeather("London");
}
#override
Widget build(BuildContext context) {
return MaterialApp(
body: FutureBuilder(
future: getData(),
builder: (context, snapshot){
if(snapshot.connectionState==ConnectionState.done){
return Column(
children: [
GuncelVeri(Icons.wb_sunny_rounded, "${data?.derece}", "${data?.sehir}"),
bilgiler("${data?.humidity}","${data?.feels_like}", "${data?.pressure}","${data?.description}"),],
);
}
else if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: CircularProgressIndicator(),
);
}
return Container();
},
)
),
);
}
}
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:weatherapp/model.dart';
class WeatherApiClient{
Future<Hava>? getCurrentWeather(String? location)async{
var endpoint = Uri.parse(
"https://api.openweathermap.org/data/2.5/weather?q=$location&appid=9b6ece44d1233c111b86cacb5e3617f1&units=metric&lang=tr"
);
var response = await http.get(endpoint);
var body = jsonDecode(response.body);
print(Hava.fromJson(body));
return Hava.fromJson(body);
}
}
Your are getting Null because you are trying to access the Hava class which have not been initilized yet.
You are printing print(Hava.fromJson(body));
before return Hava.fromJson(body);
First you want to check if what responce is getting from the http call.
for that you can just print the http responce like this:-
print(responce.body)
Then you can see what's the responce is.
They you can do return Hava.fromJson(body);
The right way
Check the status code of the responce, if the responce is 200 the cast the json responce to the model class or show an error
Refer code
Future<Profileclass> fetchprofile() async {
String tokenFetch = await getStringValuesSF();
return await Dio()
.get(urlprofiledio,
options: Options(
headers: {
'Authorization': 'Bearer $tokenFetch',
},
))
.then((response) {
if (response.statusCode == 200) {
return Profileclass.fromJson(jsonDecode(response.toString()));
} else {
throw Exception('Failed to load profile');
}
});
}
Thank you

The method 'getUserData' was called on null. Receiver: null Tried calling: getUserData()

I'm trying to get the user's currency from my server. Until now I'm able to do that but the problem is the data keeps rebuild itself everytime the app gets rebuilt. I tried to fix that by this way :
Future<dynamic> userDataFuture;
ApiService apiService;
#override
void initState() {
userDataFuture = apiService.getUserData();
super.initState();
}
but fails as it gives me an error saying :
The method 'getUserData' was called on null. Receiver: null Tried calling: getUserData()
this is my ApiService Class
Future getUserData() async {
String token = await AuthProvider().getToken();
String userID = await AuthProvider().getUserId();
final response = await Dio().get(
'$apiUrl/$userID',
options: Options(headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
}),
);
if (response.statusCode == 200) {
return response.data;
} else {
throw Exception('Failed to load data');
}
}
this is my UI where I want to show the user's currency:
child: Center(
child: FutureBuilder(
future: userDataFuture,
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
"Something wrong with message: ${snapshot.error.toString()}"),
);
} else if (snapshot.connectionState ==
ConnectionState.done) {
return Text(
snapshot.data[
'currency'], // This Should Change Depending in Settings of the User
style: TextStyle(
fontSize:
(device.localWidth * .1) * .43,
fontWeight: FontWeight.w500,
color: kLightTextColor));
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
// ),
),
),
You're calling getUserData() on an ApiService object that is not initialized -- ie. null.
Instead of this
ApiService apiService;
Actually initialize it like this
final apiService = ApiService();
That will get rid of your null error. You can also just pass apiService.getUserData() into your FutureBuilder and get rid of the userDataFuture object altogether.
first of all you have to use await, here like this
userDataFuture = await apiService.getUserData();
second you have to initialize you'r apiService variable like this:
ApiService apiService = new ApiService();
third, change you'r getUserData to return some data, it's void function.
fourth one you have to use somethink like this:
setState(() {
userDateFuture = await apiService.getUserData();
});
i hope, i was able to help.

How to do stream builder to get data from bloc in flutter

I am new in BLOC and I am trying to read respond from api.. but whenever I call stream builder... my widget always stops in wait... here is my code
here is api provider file
class Provider {
final _url = '...';
Future<List<LoginRespon>> login(a, b) async {
List<LoginRespon> datalogin = [];
try {
bool trustSelfSigned = true;
HttpClient httpClient = new HttpClient()
..badCertificateCallback =
((X509Certificate cert, String host, int port) =>
trustSelfSigned);
IOClient http = new IOClient(httpClient);
final response = await http.post(_url,
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
},
body: json.encode({
"aa": a,
"bb": b,
}));
Map<String, dynamic> responseJson = json.decode(response.body);
if (responseJson["status"] == "200") {
datalogin.add(LoginRespon(
status: responseJson['status'],
data: Data(
name: responseJson['data']['name'],
position: responseJson['data']['pos'])));
return datalogin;
} else {
print("ppp");
}
} on Exception {
rethrow;
}
return datalogin;
}
}
and here is for stream builder
isClick
? StreamBuilder(
stream: bloc.login(),
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data);
return Text("success");
} else if (snapshot.hasError) {
return Text(
snapshot.error.toString());
}
return Text("wait..");
},
)
: FlatButton(
child: Text("Login"),
onPressed: () {
setState(() {
isClick = true;
});
},
),
is there a way so that I can call print(snapshot.data) inside if (snapshot.hasData)
You need to pass argument which required in method otherwise it will not successfully responce (200) and it will throw error.