Я занимаюсь разработкой мобильного приложения Flutter, которое использует API Google. На одном из экранов моего приложения я хочу позволить пользователю вводить место (город, адрес, ...) и вызывать API Google Адресов, чтобы сгенерировать список предложений на основе ввода пользователя. Всякий раз, когда ввод текста изменяется, выдается новый запрос GET.
Для обработки пользовательского ввода я использую TextEditingController, и для лучшего пользовательского опыта я хочу использовать класс FutureBuilder, чтобы при загрузке показывать загрузчик данные не готовы. Это код:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
class Info extends StatefulWidget {
static const routeName = '/info';
@override
_InfoState createState() => _InfoState();
}
class _InfoState extends State<Info> {
final controller = TextEditingController();
@override
void initState() {
// Start listening to changes.
controller.addListener(buildPredictionList);
super.initState();
}
@override
void dispose() {
// Clean up the controller when the widget is disposed.
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Info'),
),
body: Column(
children: <Widget>[
TextField(
controller: controller,
),
Container(
height: 200,
child: buildPredictionList(),
),
],
),
);
}
Widget buildPredictionList() {
return FutureBuilder(
future: fetchPredictions, // <-- Error! fetchPredictions expects a parameter!
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Prediction pred = snapshot.data[index];
return Card(
child: ListTile(
leading: Icon(Icons.pin_drop),
title: Text('${pred.description}'),
),
);
},
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return CircularProgressIndicator();
},
);
}
}
class Prediction {
final String placeId;
final String description;
Prediction({this.placeId, this.description});
factory Prediction.fromJson(Map<String, dynamic> json) {
return Prediction(
placeId: json['place_id'],
description: json['description'],
);
}
}
Future<List<Prediction>> fetchPredictions(String query) async {
const GOOGLE_API_KEY = '...';
final lat = 40.758058;
final lng = -73.985626;
final radius = 2000;
final lang = 'en';
var url =
'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$query&key=$GOOGLE_API_KEY&location=$lat,$lng&radius=$radius&language=$lang&strictbounds=true';
final response = await http.get(url);
if (response.statusCode == 200) {
var predictionsJson = json.decode(response.body)['predictions'] as List;
List<Prediction> predictions = predictionsJson
.map((predictionJson) => Prediction.fromJson(predictionJson))
.toList();
return predictions;
} else {
throw Exception('Failed to fetch Predictions');
}
}
Моя асинхронная c функция fetchPredictions
ожидает аргумент, который является строкой запроса, используемой для запроса GET (таким образом, адрес ввода, город, ...). Но я не могу обернуть это в анонимную функцию, потому что аргумент future
ожидает тип возврата Future
.
Заранее спасибо!