我正在制作一个通过JSON解析获取值的应用。我的应用程序有多个标签,但是每次在标签之间滑动时,JSON每次都会发送一个新的读取请求。下面是我的代码:
Home.dart(按住导航选项卡)
import 'package:flutter/material.dart'; import './First.dart' as first; import './Second.dart' as second; import './Third.dart' as third; import './Fourth.dart' as fourth; import './Fifth.dart' as fifth; class HomePage extends StatefulWidget { @override _HomePageState createState() => new _HomePageState(); } class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin { final List<NewPage> _tabs = [ new NewPage(title: "Providers Near Me",color: Colors.blue[500]), new NewPage(title: "Providers Search",color: Colors.blueGrey[500]), new NewPage(title: "Providers List",color: Colors.teal[500]), new NewPage(title: "My Info",color: Colors.indigo[500]), new NewPage(title: "My Dependents Info",color: Colors.red[500]), ]; NewPage _myHandler; TabController tabController; String pos = 'top'; void initState(){ super.initState(); tabController = new TabController(length: 5, vsync: this); _myHandler = _tabs[0]; tabController.addListener(_handleSelected); } void _handleSelected() { setState(() { _myHandler = _tabs[tabController.index]; }); } @override void dispose() { tabController.dispose(); super.dispose(); } /// /// This method defines the different tabs in the Tab Bar. This is the /// constructor for the Navigation Bar that will be used by the user most. /// TabBar navbar (){ return TabBar( controller: tabController, tabs: <Widget>[ new Tab( icon: new Icon(Icons.healing), ), new Tab( icon: new Icon(Icons.search), ), new Tab( icon: new Icon(Icons.list), ), new Tab( icon: new Icon(Icons.person), ), new Tab( icon: new Icon(Icons.group), ), ], ); } /// /// This method returns the App Bar properties. Its takes in an argument to /// determining if the Tab Bar should be at the top or at the bottom of the /// screen. If the Tab Bar is to be at the top of the screen, it will return /// the AppBar with the bottom property. If the Tab Bar is to be at the /// bottom, it will return the AppBar without the bottom property /// AppBar barController(String position){ if (position == 'top'){ return AppBar( title: new Text(_myHandler.title), backgroundColor: _myHandler.color, bottom: navbar(), ); } else if (position == 'bottom'){ return AppBar( title: new Text(_myHandler.title), backgroundColor: _myHandler.color, ); } else{ return null; } } /// /// This method controls the Navigation Bar at the bottom of the page. If the /// navigation bar is to be displayed at the bottom, then the navigation bar /// will be returned. Else, null will be returned. /// Material bottomBarController(String disp){ if (disp == 'bottom'){ return Material( color: _myHandler.color, child: navbar(), ); } else{ return null; } } @override Widget build(BuildContext context){ return new Scaffold( endDrawer: new AppDrawer(), appBar: barController(pos), body: new TabBarView( children: <Widget>[ new first.First(), new second.MapPage(), new third.Third(), new fourth.Fourth(), new fifth.Fifth(), ], controller: tabController, ), bottomNavigationBar: bottomBarController(pos) ); } } // Appdrawer // This method opens a drawer where more settings are available to control // according to user needs. class AppDrawer extends StatefulWidget { @override _AppDrawerState createState() => _AppDrawerState(); } class _AppDrawerState extends State<AppDrawer> { bool _value = false; String message = "This is true"; void onChanged(bool value){ if(value){ setState(() { message = "This is true"; print(message.toString()); String pos = "top"; _value = true; }); }else{ setState(() { message = "This is false"; print(message.toString()); String pos = "bottom"; _value = false; }); } } @override Widget build(BuildContext context) { return Drawer( child: new ListView( children: <Widget>[ new UserAccountsDrawerHeader( accountName: new Text("Suman Kumar"), accountEmail: new Text ("Shoeman360@gmail.com"), ), new ListTile( title: new Text("Settings"), trailing: new Icon(Icons.settings), ), new SwitchListTile( title: new Text("NavBar Position"), activeColor: Colors.indigo, value: _value, onChanged: (bool value){ onChanged(value); new Text (message); } ), new ListTile( title: new Text("Close"), trailing: new Icon(Icons.cancel), onTap: () => Navigator.pop(context), ), ], ), ); } } class NewPage { final String title; final Color color; NewPage({this.title,this.color}); }
Fourth.dart(调用JSON API的类之一)
import 'package:flutter/material.dart'; import 'package:emas_app/Dependant.dart' as Dep; import 'dart:async'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'model/crm_single_user_model.dart'; final String url = "http://crm.emastpa.com.my/MemberInfo.json"; //Future class for single user information Future<SingleUser> fetchUser() async{ final response = await http.get(url); final jsonresponse = json.decode(response.body); return SingleUser.fromJson(jsonresponse[0]["Employee"]); } Future<String> jsonContent() async { var res = await http.get( Uri.encodeFull( "http://crm.emastpa.com.my/MemberInfo.json"), headers: {"Accept": "application/json"}); return res.body; } class Fourth extends StatefulWidget { @override FourthState createState() { return new FourthState(); } } class FourthState extends State<Fourth> { //String name; @override Widget build(BuildContext context) { //New body widget Widget newbody = new Container( child: new Center( child: new FutureBuilder( future: fetchUser(), builder: (context, snapshot) { if (snapshot.hasData) { var userdata = snapshot.data; //get the data from snapshot final name = userdata.name; final id = userdata.identification; final company = userdata.company; final dob = userdata.dob; return new Card( child: new Column( children: <Widget>[ new ListTile( title: new Text("Name"), subtitle: new Text(name), ), new ListTile( title: new Text("Identification"), subtitle: new Text(id), ), new ListTile( title: new Text("Company"), subtitle: new Text(company), ), new ListTile( title: new Text("Date of Birth"), subtitle: new Text(dob), ), const Divider( color: Colors.white, height: 50.0, ), new MaterialButton( color: Colors.indigo, height: 50.0, minWidth: 50.0, textColor: Colors.white, child: new Text("More"), onPressed: (){ Navigator.push(context, new MaterialPageRoute( builder: (context) => new Dep.Dependents(name: name,) )); }, ), ], ), ); } else if(snapshot.hasError){ return new Text(snapshot.error); } return new Center( child: new CircularProgressIndicator(), ); }, ), ), ); return new Scaffold( body: newbody, ); } }
crm_single_user_model.dart(Fourth.dart模型类)
class SingleUser{ final String name, identification, company, dob; SingleUser({this.name, this.identification, this.company, this.dob}); factory SingleUser.fromJson(Map<String, dynamic> ujson){ return SingleUser( name: ujson["Name"].toString(), identification: ujson["Identification"].toString(), company: ujson["Company"].toString(), dob: ujson["DateOfBirth"].toString() ); } }
有什么方法可以在 Home.dart中 仅调用一次api,而不是每次我进入 Fourth.dart时都 重复发送新的读取请求吗?
非常感谢您的协助。
问题出在您的build方法上,尤其是您要做的部分:
build
new FutureBuilder( future: fetchUser(),
基本上,如果您build因任何原因再次在何处被呼叫,您将fetchUser再次呼叫。
fetchUser
为什么要再次调用build? 我从来没有做过setState
setState
setState这不是重建小部件的唯一方法。小部件可以重建的另一种情况是其父级更新(并创建了新的子实例)。
通常,您应该假定build可以随时调用。因此,您应该在那里做最少的工作。
为了解决这个问题,您应该将自己的fetchUser未来存储在您的州内。从调用initState。这将确保fetchUser在窗口小部件创建时仅调用一次。
initState
class FourthState extends State<Fourth> { Future<SingleUser> userFuture; @override void initState() { userFuture = fetchUser(); super.initState(); } @override Widget build(BuildContext context) { return FutureBuilder( future: userFuture, builder: ... ); } }