如何在Flutter中仅解析一次JSON [英] How to parse JSON only once in Flutter

查看:81
本文介绍了如何在Flutter中仅解析一次JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个通过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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆