如何处理错误"getter在null上被调用",方法是使用flutter块从fire存储中使用依赖项



FireStore:检索数据时,我面临如下错误

The following NoSuchMethodError was thrown building BlocBuilder<AppCubit, AppStates>(dirty, state: _BlocBuilderBaseState<AppCubit, AppStates>#783ea):
The getter 'cover' was called on null.
Receiver: null
Tried calling: cover

所以意识到这个错误是因为dependency injection,我发现userModelnull,这是我的userModel类:

class UserModel {
String name;
String email;
String phone;
String uId;
String image;
String cover;
String bio;
bool isEmailVerified;
UserModel({
this.name,
this.email,
this.phone,
this.uId,
this.image,
this.cover,
this.bio,
this.isEmailVerified,
});
UserModel.fromJson(Map<String, dynamic> json) {
email = json['email'];
name = json['name'];
phone = json['phone'];
uId = json['uId'];
image = json['image'];
cover = json['cover'];
bio = json['bio'];
isEmailVerified = json['isEmailVerified'];
}
Map<String, dynamic> toMap() {
return {
'name': name,
'email': email,
'phone': phone,
'uId': uId,
'image': image,
'cover': cover,
'bio': bio,
'isEmailVerified': isEmailVerified,
};
}
}

我在Cubit类中创建了一个getUserData方法,如下所示:

UserModel userModel;
void getUserData() {
emit(AppGetUserLoadingState());
FirebaseFirestore.instance.collection('users').doc(uId).get().then((value) {
// print(value.data());
userModel = UserModel.fromJson(value.data());
emit(
AppGetUserSuccessState(),
);
}).catchError((error) {
print(error.toString());
emit(
AppGetUserErrorState(
error.toString(),
),
);
});
}

当应用程序启动时,我调用这个方法,如下代码所示:

Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => AppCubit()..getUserData()..handleScroll(),
child: BlocConsumer<AppCubit, AppStates>(
listener: (context, state) {},
builder: (context, state) {...},
),
);
}

这是在我有错误的多个部分之一下面:

DecorationImage(
image: NetworkImage(
'${userModel.cover}',
),
fit: BoxFit.cover,
),

这是我正在使用的完整类:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mysocially/shared/cubit/cubit.dart';
import 'package:mysocially/shared/cubit/states.dart';
import 'package:mysocially/styles/icon_broken.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocConsumer<AppCubit, AppStates>(
listener: (context, state) {},
builder: (context, state) {
var userModel = AppCubit.get(context).userModel;
// print(userModel.cover);
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
height: 190.0,
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
Align(
alignment: AlignmentDirectional.topCenter,
child: Container(
width: double.infinity,
height: 140.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4.0),
topRight: Radius.circular(4.0),
),
image: DecorationImage(
image: NetworkImage(
'${userModel.cover}',
),
fit: BoxFit.cover,
),
),
),
),
CircleAvatar(
radius: 51.0,
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
child: CircleAvatar(
// radius: responsive.height * 0.025,
radius: 50.0,
backgroundImage: NetworkImage(
'${userModel.image}',
),
),
),
],
),
),
SizedBox(
height: 5.0,
),
Text(
'${userModel.name}',
style: Theme.of(context).textTheme.bodyText1,
),
Text(
'${userModel.bio}',
style: Theme.of(context).textTheme.caption,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: Row(
children: [
Expanded(
child: InkWell(
child: Column(
children: [
Text(
'100',
style: Theme.of(context).textTheme.subtitle2,
),
Text(
'Posts',
style: Theme.of(context).textTheme.caption,
),
],
),
onTap: () {},
),
),
Expanded(
child: InkWell(
child: Column(
children: [
Text(
'100',
style: Theme.of(context).textTheme.subtitle2,
),
Text(
'Posts',
style: Theme.of(context).textTheme.caption,
),
],
),
onTap: () {},
),
),
Expanded(
child: InkWell(
child: Column(
children: [
Text(
'62',
style: Theme.of(context).textTheme.subtitle2,
),
Text(
'Photos',
style: Theme.of(context).textTheme.caption,
),
],
),
onTap: () {},
),
),
Expanded(
child: InkWell(
child: Column(
children: [
Text(
'200',
style: Theme.of(context).textTheme.subtitle2,
),
Text(
'Followers',
style: Theme.of(context).textTheme.caption,
),
],
),
onTap: () {},
),
),
Expanded(
child: InkWell(
child: Column(
children: [
Text(
'600',
style: Theme.of(context).textTheme.subtitle2,
),
Text(
'Followings',
style: Theme.of(context).textTheme.caption,
),
],
),
onTap: () {},
),
),
],
),
),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {},
child: Text('Add Photos'),
),
),
SizedBox(
width: 10.0,
),
OutlinedButton(
onPressed: () {},
child: Icon(
IconBroken.Edit,
size: 20.0,
),
),
],
),
],
),
);
},
);
}
}

我试图通过使用init: Get.find(),使用GetX状态管理来处理此问题,但我未能使用flutter_bloc处理此错误。。

获取更多信息:第一次登录时没有检索到数据,但在我重新启动应用程序时检索到了数据,但它会给我一秒钟的错误,并将数据返回给我。。

有什么建议吗?

我希望我提到了所有需要的信息。。

#已编辑所以我想了一些东西,所以我在生成器开始时设置了一个条件,如下代码:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mysocially/modules/new_post/new_post_screen.dart';
import 'package:mysocially/shared/components/components.dart';
import 'package:mysocially/shared/cubit/cubit.dart';
import 'package:mysocially/shared/cubit/states.dart';
import 'package:mysocially/styles/icon_broken.dart';
class SocialLayout extends StatelessWidget {
const SocialLayout({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocConsumer<AppCubit, AppStates>(
listener: (context, state) {},
builder: (context, state) {
var cubit = AppCubit.get(context);
if (state is AppGetUserSuccessState) {
return Scaffold(
extendBody: true,
appBar: AppBar(
title: Text(
cubit.titles[cubit.currentIndex],
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(IconBroken.Notification),
),
IconButton(
onPressed: () {},
icon: Icon(IconBroken.Search),
),
],
),
body: cubit.screens[cubit.currentIndex],
bottomNavigationBar: AnimatedOpacity(
opacity: cubit.show ? 1.0 : 0.0,
duration: Duration(milliseconds: 500),
child: BottomNavigationBar(
currentIndex: cubit.currentIndex,
onTap: (index) {
cubit.changeBottomNavIndex(index);
},
items: [
BottomNavigationBarItem(
icon: Icon(IconBroken.Home), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(IconBroken.Chat), label: 'Chat'),
// BottomNavigationBarItem(
//     icon: Icon(IconBroken.Paper_Upload,), label: 'Post'),
BottomNavigationBarItem(
icon: Icon(IconBroken.Location), label: 'Location'),
BottomNavigationBarItem(
icon: Icon(IconBroken.Setting), label: 'Settings'),
],
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
floatingActionButton: AnimatedOpacity(
opacity: cubit.show ? 1.0 : 0.0,
duration: Duration(milliseconds: 500),
child: FloatingActionButton(
onPressed: () {
navigateTo(
context,
NewPostScreen(),
);
},
tooltip: 'Post',
child: Icon(
IconBroken.Paper_Upload,
color: Colors.white,
),
elevation: 2.0,
),
),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
);
}
}

现在,在我重新启动应用程序后,该应用程序运行良好,没有给我错误,但我第一次尝试登录时,它显示CircularProgressIndicator()为无穷大,直到我重新启动该应用程序并再次登录。。

这是我所有的AppStates:

abstract class AppStates {}
class AppInitialState extends AppStates {}
class AppGetUserLoadingState extends AppStates {}
class AppGetUserSuccessState extends AppStates {}
class AppGetUserErrorState extends AppStates {
final String error;
AppGetUserErrorState(this.error);
}
class AppChangeBottomNavBarState extends AppStates {}
class AppChangeBottomSheetState extends AppStates {}
class AppChangeModeState extends AppStates {}
class AppHandleReverseHideBottomWidgetState extends AppStates {}
class AppHandleForwardHideBottomWidgetState extends AppStates {}
class AppHideBottomWidgetState extends AppStates {}
class AppShowBottomWidgetState extends AppStates {}
class AppNewPostState extends AppStates {}

这是下面的LoginScreen:

import 'package:conditional_builder/conditional_builder.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mysocially/layout/social_layout.dart';
import 'package:mysocially/modules/register/register_screen.dart';
import 'package:mysocially/network/local/cache_helper.dart';
import 'package:mysocially/shared/components/components.dart';

import 'cubit/cubit.dart';
import 'cubit/states.dart';
class LoginScreen extends StatelessWidget {
var formKey = GlobalKey<FormState>();
var emailController = TextEditingController();
var passwordController = TextEditingController();
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => AppLoginCubit(),
child: BlocConsumer<AppLoginCubit, AppLoginStates>(
listener: (context, state) {
if (state is AppLoginErrorState) {
showToast(
text: state.error,
state: ToastStates.ERROR,
);
}
if(state is AppLoginSuccessState) {
CacheHelper.saveData(
key: 'uId',
value: state.uId,
).then((value)
{
navigateAndFinish(
context,
SocialLayout(),
);
});
}
},
builder: (context, state) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'LOGIN',
style: Theme.of(context).textTheme.headline4.copyWith(
color: Colors.black,
),
),
Text(
'Login now to to contact with friends',
style: Theme.of(context).textTheme.bodyText1.copyWith(
color: Colors.grey,
),
),
SizedBox(
height: 30.0,
),
defaultFormField(
controller: emailController,
type: TextInputType.emailAddress,
validate: (String value) {
if (value.isEmpty) {
return 'please enter your email address';
}
},
label: 'Email Address',
prefix: Icons.email_outlined,
),
SizedBox(
height: 15.0,
),
defaultFormField(
controller: passwordController,
type: TextInputType.visiblePassword,
suffix: AppLoginCubit.get(context).suffix,
onSubmit: (value) {
if (formKey.currentState.validate()) {
AppLoginCubit.get(context).userLogin(
email: emailController.text,
password: passwordController.text,
);
}
},
isPassword: AppLoginCubit.get(context).isPassword,
suffixPressed: () {
AppLoginCubit.get(context)
.changePasswordVisibility();
},
validate: (String value) {
if (value.isEmpty) {
return 'password is too short';
}
},
label: 'Password',
prefix: Icons.lock_outline,
),
SizedBox(
height: 30.0,
),
ConditionalBuilder(
condition: state is! AppLoginLoadingState,
builder: (context) => defaultButton(
function: () {
if (formKey.currentState.validate()) {
AppLoginCubit.get(context).userLogin(
email: emailController.text,
password: passwordController.text,
);
}
},
text: 'login',
isUpperCase: true,
),
fallback: (context) =>
Center(child: CircularProgressIndicator()),
),
SizedBox(
height: 15.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Don't have an account?',
),
defaultTextButton(
function: () {
navigateTo(
context,
AppRegisterScreen(),
);
},
text: 'register',
),
],
),
],
),
),
),
),
),
);
},
),
);
}
}

我认为您的主要困惑源于您使用(至少在名称上(Cubit这一事实。Cubit是要与单个值一起使用的高度简化类型的Bloc。例如"颜色"、数字或枚举值。

你没有。您有复杂数据的列表。您应该使用全吹Bloc。flatter_bloc页面上有非常好的教程。请不要停留在简单的教程上,阅读一本关于复杂数据的教程,因为这就是你所拥有的。

主要区别在于,您不再直接访问Bloc获取数据,所有数据都通过状态进行通信。例如,Bloc没有属性User,只有UserSuccessfullyLoaded状态具有该属性。这样,当这些数据可用和不可用时,编译器将为您提供指导。

最新更新