如何在Flutter中仅解析一次JSON [英] How to parse JSON only once in Flutter
问题描述
我正在制作一个通过JSON解析获取值的应用。我的应用程序有多个标签,但是每次在标签之间滑动时,JSON每次都会发送一个新的读取请求。下面是我的代码:
I am making an app which takes values through JSON parsing. My app has multiple tabs but each time im swiping between tabs, the JSON sends a new read request every time. Below is my code:
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()
);
}
}
是否有任何方法可以一次调用api Home.dart ,而不是每次我进入 Fourth.dart 时都重复发送新的读取请求吗?
Is there any way to call the api just once in Home.dart and not repeatedly send a new read request everytime i go into Fourth.dart?
任何帮助
推荐答案
您的问题来自您的 build
方法具体是您要做的部分:
You problem comes from your build
method.Specifically the part where you do:
new FutureBuilder(
future: fetchUser(),
基本上,如果您的 build
由于任何原因再次被调用,您会再次调用 fetchUser
。
Basically, if your build
where to be called again for any reason, you would call fetchUser
again.
为什么build再会被调用吗?我从没做过 setState
Why build would be called again? I never did a setState
setState
并不是唯一可以重建的小部件,而可以重建的另一种情况是当其父级更新(并创建了一个新的子实例)时。
setState
is not the only way a widget can get rebuilt. Another situation where a widget can get rebuilt is when its parent updates (and created a new child instance).
通常,你应该应该假定可以随时调用 build
。因此,您应该在此完成最少的工作。
In general, you should assume that build
can be called at any time. Therefore you should do the least amount of work there.
要解决此问题,您应该存储 fetchUser
您所在州的未来。从 initState
调用。这样可以确保在创建小部件时仅调用一次 fetchUser
。
To solve this problem, you should store your fetchUser
future inside your state. Called from the initState
. This will ensure that the fetchUser
is called only once at the widget creation.
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: ...
);
}
}
这篇关于如何在Flutter中仅解析一次JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!