弹出后提供者为空
Provider null after pop
我正在尝试使用具有 MVVM 架构的 Provider,我在 provider 上有一个非常奇怪的错误,在主页上有 3 个部分,横幅,折扣和类别,当我更改折扣中的商品数量时,一切正常,但是切换到一个类别并返回后,当我更改商品数量时它已经给出了错误,
数据不为空,我认为是provider的问题,方案如下:
discount section-> quantity of goods -> works
home-> category-> go back-> quantity of goods in discounts-> not working
演示 project
The following _CastError was thrown building MainPage(dirty, dependencies: [_InheritedProviderScope<AllGoodsViewModel?>, _LocalizationsScope-[GlobalKey#a9792], MediaQuery, _InheritedProviderScope<MainPageListViewModel?>], state: _MainPageState#eb568):
Null check operator used on a null value
The relevant error-causing widget was:
MainPage MainPage:file:///Users/.../lib/main.dart:93:21
When the exception was thrown, this was the stack:
#0 Element.widget (package:flutter/src/widgets/framework.dart:3229:31)
#1 debugCheckHasMediaQuery.<anonymous closure> (package:flutter/src/widgets/debug.dart:245:17)
#2 debugCheckHasMediaQuery (package:flutter/src/widgets/debug.dart:261:4)
#3 MediaQuery.of (package:flutter/src/widgets/media_query.dart:908:12)
#4 ScreenUtil.screenWidth (package:flutter_screenutil/src/screen_util.dart:148:37)
#5 ScreenUtil.scaleWidth (package:flutter_screenutil/src/screen_util.dart:167:28)
#6 ScreenUtil.setWidth (package:flutter_screenutil/src/screen_util.dart:182:41)
#7 SizeExtension.w (package:flutter_screenutil/src/size_extension.dart:9:32)
#8 _MainPageState.build (package:.../View/MainPage.dart:240:78)
#9 StatefulElement.build (package:flutter/src/widgets/framework.dart:4919:27)
#10 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4806:15)
#11 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4977:11)
#12 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)
#13 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2659:19)
#14 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:891:21)
#15 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:370:5)
#16 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1146:15)
#17 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1083:9)
#18 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:997:5)
#22 _invoke (dart:ui/hooks.dart:151:10)
#23 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:308:5)
#24 _drawFrame (dart:ui/hooks.dart:115:31)
(elided 3 frames from dart:async)
ScreenUtilInitService
class ScreenUtilInitService z{
/// A helper widget that initializes [ScreenUtil]
ScreenUtilInitService({required this.builder, Key? key,}) : super(key: key);
final Widget Function(BuildContext) builder;
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(375, 812),
builder: (context, widget) => builder(context)
);
}
}
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _initialized = false;
bool _error = false;
Widget _present = SplashScreen();
void initializeFlutterFire() async {
try {
if (Platform.isAndroid) {
await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
}
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await message();
await rootWidget();
setState(() {
_initialized = true;
});
} catch(e) {
setState(() {
_error = true;
});
}
}
Future<void> rootWidget() async {
final prefs = await SharedPreferences.getInstance();
final id = prefs.get("idAddress");
final logged = prefs.getBool("logged") ?? false;
if ((FirebaseAuth.instance.currentUser?.uid != null && logged) || id != null) {
setState(() {
_present = MainPage();
});
return;
} else {
setState(() {
_present = OfferPage();
});
return;
}
}
@override
void initState() {
initializeDB();
initializeFlutterFire();
super.initState();
listeners();
}
@override
Widget build(BuildContext context) {
if(_error) {
return MaterialApp(home:SplashScreen());
}
if (!_initialized) {
return MaterialApp(home:SplashScreen());
}
return RootPage().mainPage(present: _present);
}
}
和 RootPage
class RootPage {
Widget mainPage({Widget? present}){
return MaterialApp(
initialRoute: '/',
routes: {
'/ProfilePage': (context) => ProfilePage(),
'/MainPage': (context) => MainPage(),
'/CartPage': (context) => CartPage(),
},
builder: (context, widget) {
return ScreenUtilInitService(
builder: (context) => widget!
);
},
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => MainPageListViewModel(),
),
ChangeNotifierProvider(
create: (context) => CartViewModel(),
child: CartPage()
),
ChangeNotifierProvider(
create: (context) => AllGoodsViewModel(),
),
ChangeNotifierProvider(
create: (context) => GoodsViewModel(),
),
],
child: present != null ? present : MainPage(),
),
);
}
}
主页
@override
void initState() {
setting();
super.initState();
_scrollListener();
_notification();
}
@override
void dispose() {
_scrollController.removeListener(() { });
_scrollController.dispose();
NotificationCenter().unsubscribe('cart');
NotificationCenter().unsubscribe('address');
super.dispose();
}
void setting() async {
final cart = await SQFliteService.cart.getCount();
final address = await SQFliteService.location.current();
setState((){
_address = address;
showCart = cart == 0 ? false : true;
});
Provider.of<MainPageListViewModel>(context, listen: false).deliveryRequest() ;
Provider.of<MainPageListViewModel>(context, listen: false).fetchBanner();
Provider.of<MainPageListViewModel>(context, listen: false).fetchCategory();
Provider.of<AllGoodsViewModel>(context, listen: false).fetchSale();
Provider.of<MainPageListViewModel>(context, listen: false).fetchLaunchMessage(context);
}
void _scrollListener(){
_scrollController.addListener(() {
///setState is null after pop after category
// setState(() {
// _bottomOffSet = _scrollController.offset;
// });
});
}
void _notification(){
NotificationCenter().subscribe('cart', () async {
final result = await SQFliteService.cart.getCount();
setState(() {
showCart = result == 0 ? false : true;
print("update");
});
});
NotificationCenter().subscribe('address', () async {
final result = await SQFliteService.location.current();
setState((){
_address = result;
});
});
}
@override
Widget build(BuildContext context) {
final models = Provider.of<MainPageListViewModel>(context);
final sale = Provider.of<AllGoodsViewModel>(context);
final size = MediaQuery.of(context).size;
return Container(
child: CustomScrollView(
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
slivers: [
SliverAppBar(
...
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) => Container(
color: Colors.transparent,
child: Column(
children: [
bannerW(),
ViewSale(model: sale.goods),
SizedBox(height: 10),
ViewCategory(model: models.category)
]
),
),
childCount: 1
),
),
],
),
);
ViewSale
class _ViewSaleState extends State<ViewSale> {
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
margin: EdgeInsets.only(left: 16, right: 16, bottom: 15),
child: Align(
alignment: Alignment.centerLeft,
child: Text("Скидки", style: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w900, fontSize: 18))),
),
Container(
height: ((MediaQuery.of(context).size.width/2.4) - 21) + 71,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
shrinkWrap: true,
itemCount: widget.model.length,
scrollDirection: Axis.horizontal,
itemBuilder: (item, index) {
return ChangeNotifierProvider(
create: (context) => AllGoodsViewModel(),
child: ViewGoodsSale(model: widget.model[index])
);
}),
)
]
);
}
}
查看销售商品
class _ViewGoodsSaleState extends State<ViewGoodsSale> {
GlobalKey _key = GlobalKey();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
Provider.of<AllGoodsViewModel>(context, listen: false).setting(widget.model);
});
}
@override
Widget build(BuildContext context) {
final model = Provider.of<AllGoodsViewModel>(context);
final size = MediaQuery.of(context).size;
Widget inCart(){
return Container(
key: _key,
height: 31,
child: GestureDetector(
onPanDown: (details) {
Goods? item = widget.model;
RenderBox _cardBox = _key.currentContext!.findRenderObject() as RenderBox;
final localPosition = details.localPosition;
final localDx = localPosition.dx;
if (localDx <= _cardBox.size.width/2) {
Goods value = cart.firstWhere((element) => element.id == item.id);
if (item.optState == 0 ? value.orderCount <= 1 : value.orderCount <= value.opt!.count) {
setState(() {
context.read<AllGoodsViewModel>().setCountInCart(0);
final ind = cart.indexWhere((element) => element.id == item.id);
if (ind != -1) {
cart[ind].orderCount = 0;
SQFliteService.cart.delete(cart[ind].id);
cart.removeAt(ind);
}
});
} else {
model.haveItem(item: item, operation: item.optState == 0 ? -1 : (-1 * value.opt!.count));
}
} else {
model.haveItem(item: item, operation: item.optState == 0 ? 1 : item.count);
}
},
child: TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Design.appColor),
padding: MaterialStateProperty.all(EdgeInsets.symmetric(vertical: 8, horizontal: 10)),
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
))
),
onPressed: (){},
child: Container(
child: RichText(
text: TextSpan(
text: "",
children:[
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(Icons.remove, size: 14, color: Colors.white),
),
TextSpan(
text: " ${widget.model.optState == 0 ? (widget.model.minPrice ?? widget.model.price) : widget.model.opt!.price} ₽ ",
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Inter"
),
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(Icons.add, size: 14, color: Colors.white),
)
],
),
),
),
),
),// Your TextButton code goes here.
);
}
Widget noInCart(){
return Container(
key: _key,
height: 31,
child: TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(model.orderBg),
padding: MaterialStateProperty.all(EdgeInsets.symmetric(vertical: 8, horizontal: 10)),
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
))
),
onPressed: (){
Goods? item = widget.model;
model.haveItem(item: item, operation: item.optState == 0 ? 1 : item.count);
},
child: Container(
child: RichText(
text: TextSpan(
text: "${widget.model.optState == 0 ? widget.model.minPrice == null ? widget.model.price : widget.model.minPrice : widget.model.opt!.price} ₽ ",
style: TextStyle(
color: widget.model.minPrice != null ? Design.grey : Colors.black,
decoration: widget.model.optState == 0 && widget.model.minPrice != null ? TextDecoration.lineThrough : TextDecoration.none,
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Inter"
),
children:[
TextSpan(
text: widget.model.minPrice == null ? "" : " ${widget.model.price} ₽",
style: TextStyle(
color: Colors.black,
decoration: TextDecoration.none,
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Inter"
),
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(Icons.add, size: 14, color: Colors.black),
style: TextStyle(
color: Colors.black,
decoration: TextDecoration.none,
),
)
],
),
),
),
),
);
}
Widget card({required Size size}) {
return Container(
color: Colors.white,
width: (size.width/2.4) - 11,
margin: EdgeInsets.only(right: 10),
child: Column(
children: [
Stack(
children: [
Container(
height: (size.width/2.4) - 21,
padding: EdgeInsets.all(1),
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.contain,
image: NetworkImage(widget.model.images.first)
),
borderRadius: BorderRadius.all(Radius.circular(10.0)),
border: Border.all(
width: 1,
color: Design.lightGrey
),
),
),
Visibility(
visible: context.read<AllGoodsViewModel>().countInCart == 0 ? false : true,
child: Container(
height: (size.width/2.4) - 21,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
child: Visibility(
visible: true,
child: Center(
child: model.orderCountText,
),
),
),
)
]
),
SizedBox(height: 5),
Align(
alignment: Alignment.centerLeft,
child: Container(
height: 29,
child: Text(widget.model.name,
maxLines: 2,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w700,
fontFamily: "Inter",
),
),
),
),
SizedBox(height: 6),
Align(
alignment: Alignment.centerLeft,
child: (context.read<AllGoodsViewModel>().countInCart == 0) ? noInCart() : inCart()
)
],
),
);
}
return card(size: size);
}
}
查看类别
class _ViewCategoryState extends State<ViewCategory> {
@override
Widget build(BuildContext context) {
return Container(
child: GridView.builder(
padding: EdgeInsets.all(16),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1),
itemCount: widget.model.length,
itemBuilder: (context, index) {
return GestureDetector(
child: Stack(
children: [
Container(
decoration: BoxDecoration(
color: Design.lightGrey,
borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
margin: EdgeInsets.only(right: (index.isOdd ? 0 : 5) , left: (index.isOdd ? 5 : 0), bottom: 10 ),
child: Image.network(widget.model[index].category?.url ?? "")
),
Positioned(
left: 10,
right: 10,
top: 8,
child: Text(widget.model[index].category?.name ?? "", style: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w500, fontSize: 12.sp)),
)
]
),
onTap: () async {
if (widget.model[index].category != null) {
final data = widget.model[index].category!;
final category = CategoryData(id: data.id, name: data.name);
if (data.tags == null) {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) =>
ChangeNotifierProvider.value(value: AllGoodsViewModel(),
child: AllCategoryGoodsPage(category: category))
)
);
} else {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) =>
ChangeNotifierProvider.value(value: GoodsViewModel(),
child: GoodsPage(category: category))
)
);
}
FirebaseAnalytics.instance.logEvent(name: "Category", parameters: null);
}
}
);
},
),
);
}
}
"Give a man a fish, feed him for a day. Teach a man to fish, feed him for a lifetime."
因此,我尝试解释一般情况下该做什么。
首先,查看错误堆栈跟踪。您只提供错误 message 而没有 stacktrace - 因此难怪没人能看到哪一行代码引发了错误。
P.S。如果找不到堆栈跟踪,请搜索或创建一个单独的问题(在某些奇怪的情况下堆栈跟踪不容易找到)。
当您获得堆栈跟踪时,您可以了解哪行代码有此空指针错误,以及哪些行正在调用该函数。假设它是 a.dart
行 123
抛出错误,然后查看该行并检查为什么会发生这种情况。
您可能想要进行“记录”或“调试”以挖掘更多线索。
那么错误应该很容易找到并解决。如果没有,请尝试创建一个 最小 可重现样本 - 您当前的样本仍然很大,人们很难为您挖掘和发现错误 :)
"空值检查运算符 " 是在未初始化的可空实例上使用 bang 运算符 (!) 时出现的错误。
在您的“ViewSaleGoods”文件中,它位于 -
if (item.optState == 0 ? value.orderCount <= 1 : value.orderCount <= value.opt!.count) { // Here .....
setState(() {
context.read<AllGoodsViewModel>().setCountInCart(0);
final ind = cart.indexWhere((element) => element.id == item.id);
if (ind != -1) {
cart[ind].orderCount = 0;
SQFliteService.cart.delete(cart[ind].id);
cart.removeAt(ind);
}
});
} else {
model.haveItem(item: item, operation: item.optState == 0 ? -1 : (-1 * value.opt!.count)); // here...
}
TextSpan(
text: " ${widget.model.optState == 0 ? (widget.model.minPrice ?? widget.model.price) : widget.model.opt!.price} ₽ ", // and here ....
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Inter"
),
),
所以这些人中的任何一个都变成了 null,所以错误。现在要修复它,您可以使用一些方法,例如 -
// Use variable and if check
var nullSafe;
if (value.opt != null) {
nullSafe = value.opt; // now you can use these variable instead
}
// Or use ?. and ??
value.opt?count ?? "some default value"
希望对您有所帮助。
您的 IDE 通常会有很好的堆栈跟踪调试。如果您正在使用 vscode,您可以为错误跟踪打开以下两个选项。
如果您使用的是 Android Studio。 运行 -> 查看断点。
我解决了问题,错误根本不是在provider,而是在ScreenUtilInitService我改成了
class ScreenUtilInitService {
Widget build(Function(BuildContext) builder) {
return ScreenUtilInit(
designSize: Size(375, 812),
builder: (context, widget) => builder(context)
);
}
}
并从 GoodsPage
和 AllCategoryGoodsPage
中删除了 ScreenUtilInitService
,因此 ScreenUtilInitService
未被重新定义为小部件,这导致了错误
我正在尝试使用具有 MVVM 架构的 Provider,我在 provider 上有一个非常奇怪的错误,在主页上有 3 个部分,横幅,折扣和类别,当我更改折扣中的商品数量时,一切正常,但是切换到一个类别并返回后,当我更改商品数量时它已经给出了错误, 数据不为空,我认为是provider的问题,方案如下:
discount section-> quantity of goods -> works
home-> category-> go back-> quantity of goods in discounts-> not working
演示 project
The following _CastError was thrown building MainPage(dirty, dependencies: [_InheritedProviderScope<AllGoodsViewModel?>, _LocalizationsScope-[GlobalKey#a9792], MediaQuery, _InheritedProviderScope<MainPageListViewModel?>], state: _MainPageState#eb568):
Null check operator used on a null value
The relevant error-causing widget was:
MainPage MainPage:file:///Users/.../lib/main.dart:93:21
When the exception was thrown, this was the stack:
#0 Element.widget (package:flutter/src/widgets/framework.dart:3229:31)
#1 debugCheckHasMediaQuery.<anonymous closure> (package:flutter/src/widgets/debug.dart:245:17)
#2 debugCheckHasMediaQuery (package:flutter/src/widgets/debug.dart:261:4)
#3 MediaQuery.of (package:flutter/src/widgets/media_query.dart:908:12)
#4 ScreenUtil.screenWidth (package:flutter_screenutil/src/screen_util.dart:148:37)
#5 ScreenUtil.scaleWidth (package:flutter_screenutil/src/screen_util.dart:167:28)
#6 ScreenUtil.setWidth (package:flutter_screenutil/src/screen_util.dart:182:41)
#7 SizeExtension.w (package:flutter_screenutil/src/size_extension.dart:9:32)
#8 _MainPageState.build (package:.../View/MainPage.dart:240:78)
#9 StatefulElement.build (package:flutter/src/widgets/framework.dart:4919:27)
#10 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4806:15)
#11 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4977:11)
#12 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)
#13 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2659:19)
#14 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:891:21)
#15 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:370:5)
#16 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1146:15)
#17 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1083:9)
#18 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:997:5)
#22 _invoke (dart:ui/hooks.dart:151:10)
#23 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:308:5)
#24 _drawFrame (dart:ui/hooks.dart:115:31)
(elided 3 frames from dart:async)
ScreenUtilInitService
class ScreenUtilInitService z{
/// A helper widget that initializes [ScreenUtil]
ScreenUtilInitService({required this.builder, Key? key,}) : super(key: key);
final Widget Function(BuildContext) builder;
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(375, 812),
builder: (context, widget) => builder(context)
);
}
}
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _initialized = false;
bool _error = false;
Widget _present = SplashScreen();
void initializeFlutterFire() async {
try {
if (Platform.isAndroid) {
await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
}
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await message();
await rootWidget();
setState(() {
_initialized = true;
});
} catch(e) {
setState(() {
_error = true;
});
}
}
Future<void> rootWidget() async {
final prefs = await SharedPreferences.getInstance();
final id = prefs.get("idAddress");
final logged = prefs.getBool("logged") ?? false;
if ((FirebaseAuth.instance.currentUser?.uid != null && logged) || id != null) {
setState(() {
_present = MainPage();
});
return;
} else {
setState(() {
_present = OfferPage();
});
return;
}
}
@override
void initState() {
initializeDB();
initializeFlutterFire();
super.initState();
listeners();
}
@override
Widget build(BuildContext context) {
if(_error) {
return MaterialApp(home:SplashScreen());
}
if (!_initialized) {
return MaterialApp(home:SplashScreen());
}
return RootPage().mainPage(present: _present);
}
}
和 RootPage
class RootPage {
Widget mainPage({Widget? present}){
return MaterialApp(
initialRoute: '/',
routes: {
'/ProfilePage': (context) => ProfilePage(),
'/MainPage': (context) => MainPage(),
'/CartPage': (context) => CartPage(),
},
builder: (context, widget) {
return ScreenUtilInitService(
builder: (context) => widget!
);
},
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => MainPageListViewModel(),
),
ChangeNotifierProvider(
create: (context) => CartViewModel(),
child: CartPage()
),
ChangeNotifierProvider(
create: (context) => AllGoodsViewModel(),
),
ChangeNotifierProvider(
create: (context) => GoodsViewModel(),
),
],
child: present != null ? present : MainPage(),
),
);
}
}
主页
@override
void initState() {
setting();
super.initState();
_scrollListener();
_notification();
}
@override
void dispose() {
_scrollController.removeListener(() { });
_scrollController.dispose();
NotificationCenter().unsubscribe('cart');
NotificationCenter().unsubscribe('address');
super.dispose();
}
void setting() async {
final cart = await SQFliteService.cart.getCount();
final address = await SQFliteService.location.current();
setState((){
_address = address;
showCart = cart == 0 ? false : true;
});
Provider.of<MainPageListViewModel>(context, listen: false).deliveryRequest() ;
Provider.of<MainPageListViewModel>(context, listen: false).fetchBanner();
Provider.of<MainPageListViewModel>(context, listen: false).fetchCategory();
Provider.of<AllGoodsViewModel>(context, listen: false).fetchSale();
Provider.of<MainPageListViewModel>(context, listen: false).fetchLaunchMessage(context);
}
void _scrollListener(){
_scrollController.addListener(() {
///setState is null after pop after category
// setState(() {
// _bottomOffSet = _scrollController.offset;
// });
});
}
void _notification(){
NotificationCenter().subscribe('cart', () async {
final result = await SQFliteService.cart.getCount();
setState(() {
showCart = result == 0 ? false : true;
print("update");
});
});
NotificationCenter().subscribe('address', () async {
final result = await SQFliteService.location.current();
setState((){
_address = result;
});
});
}
@override
Widget build(BuildContext context) {
final models = Provider.of<MainPageListViewModel>(context);
final sale = Provider.of<AllGoodsViewModel>(context);
final size = MediaQuery.of(context).size;
return Container(
child: CustomScrollView(
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
slivers: [
SliverAppBar(
...
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) => Container(
color: Colors.transparent,
child: Column(
children: [
bannerW(),
ViewSale(model: sale.goods),
SizedBox(height: 10),
ViewCategory(model: models.category)
]
),
),
childCount: 1
),
),
],
),
);
ViewSale
class _ViewSaleState extends State<ViewSale> {
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
margin: EdgeInsets.only(left: 16, right: 16, bottom: 15),
child: Align(
alignment: Alignment.centerLeft,
child: Text("Скидки", style: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w900, fontSize: 18))),
),
Container(
height: ((MediaQuery.of(context).size.width/2.4) - 21) + 71,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
shrinkWrap: true,
itemCount: widget.model.length,
scrollDirection: Axis.horizontal,
itemBuilder: (item, index) {
return ChangeNotifierProvider(
create: (context) => AllGoodsViewModel(),
child: ViewGoodsSale(model: widget.model[index])
);
}),
)
]
);
}
}
查看销售商品
class _ViewGoodsSaleState extends State<ViewGoodsSale> {
GlobalKey _key = GlobalKey();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
Provider.of<AllGoodsViewModel>(context, listen: false).setting(widget.model);
});
}
@override
Widget build(BuildContext context) {
final model = Provider.of<AllGoodsViewModel>(context);
final size = MediaQuery.of(context).size;
Widget inCart(){
return Container(
key: _key,
height: 31,
child: GestureDetector(
onPanDown: (details) {
Goods? item = widget.model;
RenderBox _cardBox = _key.currentContext!.findRenderObject() as RenderBox;
final localPosition = details.localPosition;
final localDx = localPosition.dx;
if (localDx <= _cardBox.size.width/2) {
Goods value = cart.firstWhere((element) => element.id == item.id);
if (item.optState == 0 ? value.orderCount <= 1 : value.orderCount <= value.opt!.count) {
setState(() {
context.read<AllGoodsViewModel>().setCountInCart(0);
final ind = cart.indexWhere((element) => element.id == item.id);
if (ind != -1) {
cart[ind].orderCount = 0;
SQFliteService.cart.delete(cart[ind].id);
cart.removeAt(ind);
}
});
} else {
model.haveItem(item: item, operation: item.optState == 0 ? -1 : (-1 * value.opt!.count));
}
} else {
model.haveItem(item: item, operation: item.optState == 0 ? 1 : item.count);
}
},
child: TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Design.appColor),
padding: MaterialStateProperty.all(EdgeInsets.symmetric(vertical: 8, horizontal: 10)),
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
))
),
onPressed: (){},
child: Container(
child: RichText(
text: TextSpan(
text: "",
children:[
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(Icons.remove, size: 14, color: Colors.white),
),
TextSpan(
text: " ${widget.model.optState == 0 ? (widget.model.minPrice ?? widget.model.price) : widget.model.opt!.price} ₽ ",
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Inter"
),
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(Icons.add, size: 14, color: Colors.white),
)
],
),
),
),
),
),// Your TextButton code goes here.
);
}
Widget noInCart(){
return Container(
key: _key,
height: 31,
child: TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(model.orderBg),
padding: MaterialStateProperty.all(EdgeInsets.symmetric(vertical: 8, horizontal: 10)),
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
))
),
onPressed: (){
Goods? item = widget.model;
model.haveItem(item: item, operation: item.optState == 0 ? 1 : item.count);
},
child: Container(
child: RichText(
text: TextSpan(
text: "${widget.model.optState == 0 ? widget.model.minPrice == null ? widget.model.price : widget.model.minPrice : widget.model.opt!.price} ₽ ",
style: TextStyle(
color: widget.model.minPrice != null ? Design.grey : Colors.black,
decoration: widget.model.optState == 0 && widget.model.minPrice != null ? TextDecoration.lineThrough : TextDecoration.none,
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Inter"
),
children:[
TextSpan(
text: widget.model.minPrice == null ? "" : " ${widget.model.price} ₽",
style: TextStyle(
color: Colors.black,
decoration: TextDecoration.none,
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Inter"
),
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(Icons.add, size: 14, color: Colors.black),
style: TextStyle(
color: Colors.black,
decoration: TextDecoration.none,
),
)
],
),
),
),
),
);
}
Widget card({required Size size}) {
return Container(
color: Colors.white,
width: (size.width/2.4) - 11,
margin: EdgeInsets.only(right: 10),
child: Column(
children: [
Stack(
children: [
Container(
height: (size.width/2.4) - 21,
padding: EdgeInsets.all(1),
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.contain,
image: NetworkImage(widget.model.images.first)
),
borderRadius: BorderRadius.all(Radius.circular(10.0)),
border: Border.all(
width: 1,
color: Design.lightGrey
),
),
),
Visibility(
visible: context.read<AllGoodsViewModel>().countInCart == 0 ? false : true,
child: Container(
height: (size.width/2.4) - 21,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
child: Visibility(
visible: true,
child: Center(
child: model.orderCountText,
),
),
),
)
]
),
SizedBox(height: 5),
Align(
alignment: Alignment.centerLeft,
child: Container(
height: 29,
child: Text(widget.model.name,
maxLines: 2,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w700,
fontFamily: "Inter",
),
),
),
),
SizedBox(height: 6),
Align(
alignment: Alignment.centerLeft,
child: (context.read<AllGoodsViewModel>().countInCart == 0) ? noInCart() : inCart()
)
],
),
);
}
return card(size: size);
}
}
查看类别
class _ViewCategoryState extends State<ViewCategory> {
@override
Widget build(BuildContext context) {
return Container(
child: GridView.builder(
padding: EdgeInsets.all(16),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1),
itemCount: widget.model.length,
itemBuilder: (context, index) {
return GestureDetector(
child: Stack(
children: [
Container(
decoration: BoxDecoration(
color: Design.lightGrey,
borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
margin: EdgeInsets.only(right: (index.isOdd ? 0 : 5) , left: (index.isOdd ? 5 : 0), bottom: 10 ),
child: Image.network(widget.model[index].category?.url ?? "")
),
Positioned(
left: 10,
right: 10,
top: 8,
child: Text(widget.model[index].category?.name ?? "", style: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w500, fontSize: 12.sp)),
)
]
),
onTap: () async {
if (widget.model[index].category != null) {
final data = widget.model[index].category!;
final category = CategoryData(id: data.id, name: data.name);
if (data.tags == null) {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) =>
ChangeNotifierProvider.value(value: AllGoodsViewModel(),
child: AllCategoryGoodsPage(category: category))
)
);
} else {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) =>
ChangeNotifierProvider.value(value: GoodsViewModel(),
child: GoodsPage(category: category))
)
);
}
FirebaseAnalytics.instance.logEvent(name: "Category", parameters: null);
}
}
);
},
),
);
}
}
"Give a man a fish, feed him for a day. Teach a man to fish, feed him for a lifetime."
因此,我尝试解释一般情况下该做什么。
首先,查看错误堆栈跟踪。您只提供错误 message 而没有 stacktrace - 因此难怪没人能看到哪一行代码引发了错误。
P.S。如果找不到堆栈跟踪,请搜索或创建一个单独的问题(在某些奇怪的情况下堆栈跟踪不容易找到)。
当您获得堆栈跟踪时,您可以了解哪行代码有此空指针错误,以及哪些行正在调用该函数。假设它是 a.dart
行 123
抛出错误,然后查看该行并检查为什么会发生这种情况。
您可能想要进行“记录”或“调试”以挖掘更多线索。
那么错误应该很容易找到并解决。如果没有,请尝试创建一个 最小 可重现样本 - 您当前的样本仍然很大,人们很难为您挖掘和发现错误 :)
"空值检查运算符 " 是在未初始化的可空实例上使用 bang 运算符 (!) 时出现的错误。
在您的“ViewSaleGoods”文件中,它位于 -
if (item.optState == 0 ? value.orderCount <= 1 : value.orderCount <= value.opt!.count) { // Here .....
setState(() {
context.read<AllGoodsViewModel>().setCountInCart(0);
final ind = cart.indexWhere((element) => element.id == item.id);
if (ind != -1) {
cart[ind].orderCount = 0;
SQFliteService.cart.delete(cart[ind].id);
cart.removeAt(ind);
}
});
} else {
model.haveItem(item: item, operation: item.optState == 0 ? -1 : (-1 * value.opt!.count)); // here...
}
TextSpan(
text: " ${widget.model.optState == 0 ? (widget.model.minPrice ?? widget.model.price) : widget.model.opt!.price} ₽ ", // and here ....
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Inter"
),
),
所以这些人中的任何一个都变成了 null,所以错误。现在要修复它,您可以使用一些方法,例如 -
// Use variable and if check
var nullSafe;
if (value.opt != null) {
nullSafe = value.opt; // now you can use these variable instead
}
// Or use ?. and ??
value.opt?count ?? "some default value"
希望对您有所帮助。
您的 IDE 通常会有很好的堆栈跟踪调试。如果您正在使用 vscode,您可以为错误跟踪打开以下两个选项。
如果您使用的是 Android Studio。 运行 -> 查看断点。
我解决了问题,错误根本不是在provider,而是在ScreenUtilInitService我改成了
class ScreenUtilInitService {
Widget build(Function(BuildContext) builder) {
return ScreenUtilInit(
designSize: Size(375, 812),
builder: (context, widget) => builder(context)
);
}
}
并从 GoodsPage
和 AllCategoryGoodsPage
中删除了 ScreenUtilInitService
,因此 ScreenUtilInitService
未被重新定义为小部件,这导致了错误