Flutter api重新加载每个导航



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

以下是我尝试过的方法:如何避免每次导航到页面 时重新加载数据如何在Flutter中只解析一次JSON

Flutter切换到选项卡会重新加载Widgets并运行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),
],
),
),
),
),
],
),
],
);
},
);
}
}

导航并返回时,将调用构建方法。这里是" myfuturebuilder "放置为Scaffold的主体小部件,从而执行此代码,在其中"方法时,它每次都从API中获取数据。

我建议你删除"myfuturebuilder"。并使用"mywirdlistview"直接作为脚手架的主体。修改myWordListView(List<Word> listOfWord)使用你已经在initState()中获取的单词列表

您需要将api调用与ui分开。这样你的api只会在你想要的时候被调用。我建议使用某种外部状态管理库,比如Provider、BLoC或RxDart。Flutter将在任何时候重建一个小部件,除了当你触发它。

您将getWord()作为函数传递给您未来的构建器,因此每次小部件得到重建时,它被称为.

要解决这个问题,声明一个变量Future<Word> getWordFuture ;,在initState内部分配getWordFuture = getWord();,并在Future构建器中使用getWordFuture。


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>> getWordFuture = Future<List<Word>> ; //1
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() {
getWordFuture = getWord(); //2
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(),
future:getWordFuture,
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),
],
),
),
),
),
],
),
],
);
},
);
}
}

最新更新