我现在遇到的问题是,无论我做什么,特定的API都会被重复调用。我已经想到了几种方法来避免这种情况,但每次我在页面之间来回移动时,这种情况都会一再发生。我必须处理的数据类型是Map<String, dynamic>
,我已经尝试过放置一个检查,您可以在下面的代码中找到它。这个检查的灵感来自于早期的一段代码,在这段代码中,我通过检查从API接收到的数据是否存在来防止重复的API调用。唯一的区别是,我必须检查的日期集是List<dynamic>
类型,下面也有相应的代码。我想知道我可以做些什么来防止在页面上来回导航时重复调用API。
运行的代码提取(List<dynamic>
)
class CategoryProvider with ChangeNotifier {
String baseUrl = 'http://*********';
List<dynamic> _category = [];
List<dynamic> get category {
return [..._category];
}
List<dynamic> get categoriesList {
return [..._categoriesList];
}
Future<void> getCategory() async {
final url = Uri.parse(baseUrl + 'api/category-list/');
print('Before Category API Call: $_category');
if (_category.length < 1) { //This here is a simple check which will basically detemine wether or not the API call needs to happen
final response = await http.get(url);
_category = json.decode(response.body);
print('CATEGORY API CALLLLLLLLL');
}
print('Categoryssssssssssssss $_category');
}
}
实现此功能的小部件:
class Categories extends StatefulWidget {
CategoriesState createState() => CategoriesState();
}
class CategoriesState extends State<Categories> {
bool isLoading = true;
@override
void initState() {
// TODO: implement initState
Provider.of<CategoryProvider>(context, listen: false)
.getCategory()
.then((_) {
setState(() {
isLoading = false;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
final width = MediaQuery.of(context).size.width;
final tabLayout = width > 600;
final largeLayout = width > 350 && width < 600;
final provider =
Provider.of<CategoryProvider>(context, listen: false).category;
return Padding(
padding: EdgeInsets.only(left: width * 0.04, right: width * 0.04),
child: Container(
width: width * 0.9,
height: !tabLayout && !largeLayout ? height * 0.28 : height * 0.25,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: const [
BoxShadow(color: Colors.grey, blurRadius: 5, offset: Offset(0, 2))
]),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(
left: width * 0.04, top: height * 0.01, right: width * 0.04),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Categories',
// textScaleFactor: textScaleFactor,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: tabLayout
? 25
: largeLayout
? 17
: 12),
),
InkWell(
onTap: () =>
Navigator.of(context).pushNamed('/category-screen'),
child: Text(
'View All',
// textScaleFactor: textScaleFactor,
style: TextStyle(
color: Colors.greenAccent,
fontSize: tabLayout
? 18
: largeLayout
? 14
: 10),
),
)
],
),
),
Expanded(
child: isLoading
? const Center(
child: CircularProgressIndicator(
color: Colors.green,
),
)
: Container(
width: double.infinity,
height: height * 0.1,
margin: EdgeInsets.only(top: height * 0.01),
padding: EdgeInsets.only(
left: width * 0.02,
top: height * 0.005,
right: width * 0.02,
bottom: height * 0.008),
decoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.circular(20),
),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => Container(
width: width * 0.3,
height: height * 0.06,
// padding: EdgeInsets.fromLTRB(width * 0.02, height * 0.01,
// width * 0.02, height * 0.01),
margin: EdgeInsets.only(right: width * 0.02),
padding: EdgeInsets.only(
left: width * 0.02, right: width * 0.02),
// color: Colors.green,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(top: height * 0.004),
child: InkWell(
onTap: () => Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => CategoryList(
provider[index]['id'],
provider[index]['name']),
)),
child: Container(
width: double.infinity,
height: tabLayout
? height * 0.14
: largeLayout
? height * 0.12
: height * 0.15,
decoration: BoxDecoration(
color: Colors.green[100],
borderRadius: BorderRadius.circular(20),
),
child: Image.network(
provider[index]['categoryImage']),
),
),
),
SizedBox(height: height * 0.01),
Text(
provider[index]['name'],
textAlign: TextAlign.center,
// textScaleFactor: textScaleFactor,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: tabLayout
? width * 0.02
: largeLayout
? 14
: 12),
)
],
),
),
itemCount: provider.length,
),
),
)
],
),
),
);
}
}
针对类型Map<String, dynamic>
进行检查的代码不起作用:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class PopularDealsProvider with ChangeNotifier {
String baseUrl = 'http://**********';
Map<String, dynamic> _popularDeals = {};
Map<String, dynamic> get popularDeals {
return {..._popularDeals};
}
Future<void> getPopularDeals() async {
print('Before API Call: $_popularDeals');
if (_popularDeals == {}) { //This check was meant to make the call only if _popularDeals was a blank Map
final url = Uri.parse(baseUrl + 'api/dashboard/popular/ordered-product/');
final response = await http.get(url);
var res = json.decode(response.body);
_popularDeals = res;
print('API Called');
}
print('PopularDeals $_popularDeals');
}
}
实现此功能的小部件:
class PopularDeals extends StatefulWidget {
PopularDealsState createState() => PopularDealsState();
}
class PopularDealsState extends State<PopularDeals> {
bool isLoading = true;
@override
void initState() {
// TODO: implement initState
Provider.of<PopularDealsProvider>(context, listen: false)
.getPopularDeals()
.then((_) {
setState(() {
isLoading = false;
});
});
itemDetail;
super.initState();
}
void itemDetail(int categoryId) async {
Provider.of<CategoryProductsProvider>(context, listen: false)
.getCategoryProducts(categoryId);
}
@override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
final width = MediaQuery.of(context).size.width;
// final textScaleFactor = MediaQuery.of(context).textScaleFactor * 1.2;
final tabLayout = width > 600;
final largeLayout = width > 350 && width < 600;
final provider = Provider.of<PopularDealsProvider>(context).popularDeals;
final productsProvider =
Provider.of<CategoryProductsProvider>(context).categoryProducts;
// TODO: implement build
return isLoading
? const Center(
child: CircularProgressIndicator(
color: Colors.green,
),
)
: Padding(
padding: EdgeInsets.only(left: width * 0.04, right: width * 0.04),
child: Container(
width: width * 0.9,
height: tabLayout
? height * 0.35
: largeLayout
? height * 0.34
: height * 0.35,
margin: EdgeInsets.only(bottom: height * 0.04),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(20),
boxShadow: const [
BoxShadow(
color: Colors.grey, blurRadius: 5, offset: Offset(0, 2))
]),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(
left: width * 0.04,
top: height * 0.01,
right: width * 0.04),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Popular Deals',
// // textScaleFactor: textScaleFactor,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: tabLayout
? 25
: largeLayout
? 17
: 12),
),
Text(
'View All',
// // textScaleFactor: textScaleFactor,
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
fontSize: tabLayout
? 18
: largeLayout
? 14
: 10),
)
],
),
),
Expanded(
child: Container(
width: double.infinity,
height: height * 0.1,
padding: EdgeInsets.fromLTRB(width * 0.02, height * 0.005,
width * 0.02, height * 0.008),
margin: EdgeInsets.only(top: height * 0.01),
decoration: const BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20)),
),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => Container(
width: tabLayout ? width * 0.35 : width * 0.45,
height: double.infinity,
margin: EdgeInsets.only(right: width * 0.02),
padding: const EdgeInsets.all(5),
// color: Colors.amber,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: const [
BoxShadow(
color: Colors.grey,
blurRadius: 5,
offset: Offset(1, 2))
]),
child: InkWell(
onTap: () => Navigator.of(context)
.pushNamed('/item-details', arguments: {
'id': provider['data'][index][0]['id'],
'image': provider['data'][index][0]
['main_image'],
'name': provider['data'][index][0]
['name'],
'quantity': 0,
'description': provider['data'][index][0]
['description'],
'price': provider['data'][index][0]
['price']
}),
child: Image.network(
'http://54.80.135.220${provider['data'][index][0]['main_image']}',
fit: BoxFit.contain,
width: tabLayout
? width * 0.35
: largeLayout
? width * 0.45
: width * 0.46,
height: tabLayout
? height * 0.24
: largeLayout
? height * 0.2
: height * 0.22,
),
),
),
SizedBox(height: height * 0.01),
Padding(
padding: EdgeInsets.only(left: width * 0.03),
child: Text(
provider['data'][index][0]['name'],
// // textScaleFactor: textScaleFactor,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: tabLayout
? width * 0.02
: largeLayout
? 14
: 12),
),
),
Padding(
padding: EdgeInsets.only(left: width * 0.03),
child: Text(
'₹${provider['data'][index][0]['price']}/${provider['data'][index][0]['uom']['short_name']}',
// // textScaleFactor: textScaleFactor,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: tabLayout
? width * 0.02
: largeLayout
? 14
: 1)),
),
]),
),
itemCount: provider['data'].length, //The error gets thrown at this line
),
),
)
],
),
),
);
}
}
以下是错误消息:
The getter 'length' was called on null.
Receiver: null
Tried calling: length
有没有人可以帮忙??
另外,我已经用List<dynamic>
类型的数据处理了这个问题。我只需要一种方法来处理Map<String, dynamic>
类型的数据
1条答案
按热度按时间e4eetjau1#
您可以使用其中任何一种方法来保存状态并防止重复的API调用:
1.索引堆栈https://api.flutter.dev/flutter/widgets/IndexedStack-class.html
1.页面存储键https://api.flutter.dev/flutter/widgets/PageStorageKey-class.html
1.自动保持活动客户端混合https://api.flutter.dev/flutter/widgets/AutomaticKeepAliveClientMixin-mixin.html