首页 > 解决方案 > Flutter api 重新加载每个导航

问题描述

每当我更改页面并返回时,都会重新加载 api。我尝试了很多建议。如果你能帮忙,我会很高兴。

以下是我尝试过的方法: 如何避免每次导航到页面时都重新加载数据

如何在 Flutter 中只解析一次 JSON

Flutter 切换到 Tab 重新加载小部件并运行 FutureBuilder

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

import 'models/Word.dart';

class WordListPage extends StatefulWidget {
  WordListPage(Key k) : super(key: k);

  @override
  _WordListPageState createState() => _WordListPageState();
}

class _WordListPageState extends State<WordListPage> {
  Future<List<Word>> data;
  bool isSearching = false;
  TextEditingController myController = TextEditingController();
  List<Word> _words = List<Word>();
  List<Word> _wordsForDisplay = List<Word>();
  var keyListPage = PageStorageKey('list_page_key');

  Future<List<Word>> getWord() async {
    var response = await http.get("myAPIurl");
    var _words = List<Word>();

    _words = (json.decode(utf8.decode(response.bodyBytes)) as List)
        .map((singleWordMap) => Word.fromJsonMap(singleWordMap))
        .toList();
    return _words;
  }

  @override
  void initState() {
    getWord().then((value) {
      setState(() {
        _words.addAll(value);
        _wordsForDisplay = _words;
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: myFutureBuilder(),
      appBar: AppBar(
        leading: Center(
          child: RichText(
            textAlign: TextAlign.center,
            text: TextSpan(
              style: DefaultTextStyle.of(context).style,
              children: <TextSpan>[
                TextSpan(
                  text: 'Total',
                  style: TextStyle(
                    decoration: TextDecoration.none,
                    fontSize: 10,
                    color: Colors.white,
                  ),
                ),
                TextSpan(
                  text: '\n${_words.length.toString()}',
                  style: TextStyle(
                    decoration: TextDecoration.none,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                    fontSize: 12,
                  ),
                ),
                TextSpan(
                  text: '\nLetter',
                  style: TextStyle(
                    decoration: TextDecoration.none,
                    color: Colors.white,
                    fontSize: 10,
                  ),
                ),
              ],
            ),
          ),
        ),
        centerTitle: true,
        title: !isSearching
            ? Text('My Title')
            : TextField(
                autofocus: true,
                style: TextStyle(color: Colors.white),
                controller: myController,
                onChanged: (value) {
                  value = value.toLowerCase();
                  setState(
                    () {
                      _wordsForDisplay = _words.where(
                        (word) {
                          var wordTitle = word.word.toLowerCase();
                          return wordTitle.contains(value);
                        },
                      ).toList();
                    },
                  );
                  setState(
                    () {
                      _wordsForDisplay = _words.where(
                        (word) {
                          var wordPronounce = word.pronunciation.toLowerCase();
                          return wordPronounce.contains(value);
                        },
                      ).toList();
                    },
                  );
                },
                decoration: InputDecoration(
                  isCollapsed: true,
                  icon: Icon(
                    Icons.menu_book,
                    color: Colors.white,
                  ),
                  hintText: 'Search',
                  hintStyle: TextStyle(color: Colors.white),
                ),
              ),
        actions: [
          isSearching
              ? IconButton(
                  icon: Icon(Icons.cancel_outlined),
                  onPressed: () {
                    setState(
                      () {
                        this.isSearching = false;
                        myController.clear();
                        _wordsForDisplay = _words.where(
                          (word) {
                            var wordTitle = word.word.toLowerCase();
                            return wordTitle.contains(wordTitle);
                          },
                        ).toList();
                      },
                    );
                  },
                )
              : IconButton(
                  icon: Icon(Icons.search_sharp),
                  onPressed: () {
                    setState(
                      () {
                        this.isSearching = true;
                      },
                    );
                  },
                ),
        ],
      ),
    );
  }

  FutureBuilder<List<Word>> myFutureBuilder() {
    return FutureBuilder(
      future: getWord(),
      builder: (context, AsyncSnapshot<List<Word>> snapshot) {
        if (snapshot.hasData) {
          return myWordListView(snapshot);
        } else {
          return Center(
            child: CircularProgressIndicator(),
          );
        }
      },
    );
  }

  ListView myWordListView(AsyncSnapshot<List<Word>> snapshot) {
    return ListView.builder(
      itemCount: _wordsForDisplay.length,
      itemBuilder: (context, index) {
        return ExpansionTile(
          title: Text(
            _wordsForDisplay[index].word,
            style: TextStyle(fontWeight: FontWeight.w500, fontSize: 16.0),
          ),
          subtitle: Text(
            snapshot.data[index].pronunciation[0].toUpperCase() +
                snapshot.data[index].pronunciation.substring(1),
          ),
          leading: CircleAvatar(
            child: Text(snapshot.data[index].word[0]),
          ),
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Container(
                  width: MediaQuery.of(context).size.width,
                  child: Padding(
                    padding: const EdgeInsets.symmetric(
                        vertical: 7.0, horizontal: 19.0),
                    child: RichText(
                      text: TextSpan(
                        style: DefaultTextStyle.of(context).style,
                        children: <TextSpan>[
                          TextSpan(
                            text: snapshot.data[index].word + ' : ',
                            style: TextStyle(fontWeight: FontWeight.bold),
                          ),
                          TextSpan(text: snapshot.data[index].meaning),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ],
        );
      },
    );
  }
}

标签: apiflutter

解决方案


当您导航并返回时,将调用 build 方法。在这里,您将“myFutureBuilder”放置为 Scaffold 的主体小部件,因此该代码被执行,在其中调用“getWord”方法,它每次都从 api 获取数据。

建议你去掉“myFutureBuider”,直接使用“myWirdListView”作为脚手架的主体。更改myWordListView(List<Word> listOfWord)为使用您已经在 initState() 中获取的单词列表。


推荐阅读