我想完成对服务器的get
请求,以便在启动时获取我的应用程序的数据。我读了几个主题,描述了构建小部件后如何运行方法。但是所有这些都是描述provider
未使用时的情况。而且我不确定在小部件内执行此请求是否是个好主意。
我尝试了几种方法,但没有成功。 这是我的代码:
void main() async {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ChangeNotifierProvider<TenderApiData>(
builder: (_) => TenderApiData(), child: HomePage()),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(), body: MainContainer());
}
}
class TenderApiData with ChangeNotifier {
String access_token;
List<Map<String, String>> id_names;
String access_token_url = "https://...";
getApiKey() async { // I need to call this method at app start up
var response = await http
.post(access_token_url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
access_token = json.decode(response.body)['access_token'];
notifyListeners();
}
}
}
class MyTestWidget extends StatefulWidget {
MyTestWidgetState createState() => MyTestWidgetState();
}
class MyTestWidgetState extends State<MyTestWidget> {
bool isKeyGetted = false;
// before I used this when I extracted data on click event.
// I am not sure that it's needed now
@override
void didChangeDependencies() {
if (!isKeyGetted) {
Provider.of<TenderApiData>(context).getApiKey();
isKeyGetted = !isKeyGetted;
}
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
if (!isKeyGetted) {
Provider.of<TenderApiData>(context).getApiKey();
isKeyGetted = !isKeyGetted;
}
var result = Provider.of<TenderApiData>(context).access_token;
var test = Provider.of<TenderApiData>(context).id_names;
return Column(
children: <Widget>[
RaisedButton(
onPressed: Provider.of<TenderApiData>(context).getRegionsList,
child: Text("get regions"),
),
],
);
}
}
class MainContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Table(
children: [
TableRow(children: [
Row(
children: <Widget>[
Container(child: MyTestWidget()),
Container(child: Text("Regions"),),
Expanded(child: SelectRegions(), )
],
)
]),
TableRow(children: [
Row(
children: <Widget>[
Text("Label"),
Text("Value"),
],
)
]),
],
);
}
}
答案 0 :(得分:0)
您可以将TenderApiData
存储为MyApp
的成员,在MyApp
构造函数中进行启动调用,然后将现有实例传递给后代。
这是它的外观:
class MyApp extends StatelessWidget {
final TenderApiData _tenderApiData = TenderApiData();
MyApp() {
_tenderApiData.getApiKey();
};
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ChangeNotifierProvider<TenderApiData>(
builder: (_) => _tenderApiData, child: HomePage()),
);
}
}
其他类别将保持不变。
另一种选择是将TenderApiData
作为构造函数参数传递到MyApp
中,使其更具可测试性。
void main() {
final TenderApiData tenderApiData = TenderApiData();
tenderApiData.getApiKey(); // call it here or in MyApp constructor - now it can be mocked and tested
runApp(MyApp(tenderApiData));
}
class MyApp extends StatelessWidget {
final TenderApiData _tenderApiData;
MyApp(this._tenderApiData);
// ...
答案 1 :(得分:0)
您可以在TenderApiData
上添加一个构造函数,以触发自定义逻辑:
class TenderApiData with ChangeNotifier {
TenderApiData() {
// TODO: call `getApiKey`
}
}
答案 2 :(得分:0)
您可以使用FutureProvider
值。
要服务的单独方法api(my_service.dart):
class MyService {
Future<String> getApiKey() async {
// I need to call this method at app start up
var response = await http
.post(access_token_url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
return json.decode(response.body)['access_token'];
}
}
}
然后从MyApp拨打电话
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureProvider<String>.value(
value: MyService().getApiKey(),
child: HomePage(),
);
}
}
在首页中:
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
String token = Provider.of<String>(context);
return Scaffold();
}
}
答案 3 :(得分:0)
你也可以只使用一个布尔标志来只运行一次。
import 'screen.abstract.dart';
class MyProvider with ChangeNotifier {
_hasInitialized = false;
// This will only be run once, when called
fetchApiOnce() {
if (_hasInitialized) {
return;
}
_hasInitialized = true;
/* DO STUFF */
}
}