I work on a shop app for learning. And when I try to get data from the API, I always have this problem:
Null check operator used on a null value
And no matter what I do I keep having this error.
void main() async
{
//this line of code ensures that all the data are set and get before running the app
WidgetsFlutterBinding.ensureInitialized();
Bloc.observer = MyBlocObserver();
DioHelper.init();
await CacheHelper.init();
Widget? widget;
bool? isDarkTheme = CacheHelper.getData(key: 'isDark') ?? false;
bool? onBoarding = CacheHelper.getData(key: 'onBoarding') ?? false;
token = CacheHelper.getData(key: 'token')??'';
print(token);
if(onBoarding != null && onBoarding)
{
widget = token.isNotEmpty? ShopLayout() : ShopLoginScreen();
}
else {
widget = OnBoardingScreen();
}
runApp(MyApp(isDarkTheme: isDarkTheme ,startWidget: widget));
}
class MyApp extends StatelessWidget
{
final bool? isDarkTheme;
final Widget? startWidget;
MyApp({@required this.isDarkTheme, @required this.startWidget});
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers:
[
BlocProvider(create: (BuildContext context) => ShopCubit()..changeAppMode(isDarkFromPreferences: isDarkTheme)),
BlocProvider(create: (BuildContext context) => ShopCubit()..getHomeData()),
BlocProvider(create: (BuildContext context) => WhatsappCubit()),
],
child: BlocConsumer<ShopCubit, ShopStates>(
listener: (context, state){},
builder: (context, state) => MaterialApp
(
theme: lightTheme,
darkTheme: darkTheme,
themeMode: ThemeMode.light,//isDarkTheme!? ThemeMode.dark: ThemeMode.dark,
debugShowCheckedModeBanner: false,
home: startWidget,
),
),
);
}
}
class ShopCubit extends Cubit<ShopStates>
{
ShopCubit() : super(ShopInitialState());
static ShopCubit get(context) => BlocProvider.of(context);
int currentIndex = 0;
bool isDark = true;
ThemeMode? appTheme;
List<Widget> screens =
[
ProductsScreen(),
CategoriesScreen(),
FavouritesScreen(),
SettingsScreen(),
];
void changeBottomSheetIndex(int index)
{
currentIndex = index;
emit(ShopChangeBottomNavCurrentIndexState());
}
HomeModel? homeModel;
void getHomeData()
{
emit(ShopLoadingHomeDataState());
DioHelper.getData(path: HOME, token: token).then((value) {
if (value.data != null) {
homeModel = HomeModel.fromJson(value.data);
print('Data fetched successfully');
printFullText(homeModel!.data!.banners[0].image);
emit(ShopSuccessHomeDataState());
}
else
{
emit(ShopErrorHomeDataState('Response data is null'));
}
}).catchError((error) {
emit(ShopErrorHomeDataState(error.toString()));
print('Error fetching data: ${error.toString()}');
});
}
void changeAppMode({bool? isDarkFromPreferences})
{
if(isDarkFromPreferences != null)
{
isDark = isDarkFromPreferences;
emit(ShopChangeAppModeState());
}
else
{
isDark = !isDark;
}
if(isDark)
{
appTheme = ThemeMode.dark;
CacheHelper.saveData(key: 'isDark', value: isDark).then((value)
{
emit(ShopChangeAppModeState());
}).catchError((error)
{
print('An error occurred while trying to set a new value as a shared preference');
});
} else
{
appTheme = ThemeMode.light;
CacheHelper.saveData(key: 'isDark', value: isDark).then((value)
{
emit(ShopChangeAppModeState());
}).catchError((error)
{
print('An error occurred while trying to set a new value as a shared preference');
});
}
}
}
class DioHelper {
static Dio? dio;
static void init() {
dio = Dio(
BaseOptions(
baseUrl: 'https://student.valuxapps.com/api/',
receiveDataWhenStatusError: true,
),
);
}
static Future<Response> getData({
@required String? path,
Map<String, dynamic>? query,
String lang = 'en',
String? token,
})
async
{
dio!.options.headers = {
'Content-Type':'application/json',
'lang':lang,
'Authorization':token??'',
};
return await dio!.get(path!, queryParameters: query!);
}
static Future<Response> postData({
@required String? url,
Map<String, dynamic>? query,
@required Map<String, dynamic>? data,
String lang = 'en',
String? token,
}) async
{
dio!.options.headers = {
'Content-Type':'application/json',
'lang':lang,
'Authorization':token??'',
};
return dio!.post(url!, queryParameters: query, data: data);
}
}
class CacheHelper
{
static SharedPreferences? sharedPreferences;
static Future<void> init() async
{
sharedPreferences = await SharedPreferences.getInstance();
}
static dynamic getData({@required String? key})
{
if(sharedPreferences == null) {
return 'error this value is null';
}
return sharedPreferences!.get(key!);
}
static Future<bool> saveData({
@required String? key,
@required dynamic value,
}) async
{
if(value is String) return await sharedPreferences!.setString(key!, value);
if(value is int) return await sharedPreferences!.setInt(key!, value);
if(value is bool) return await sharedPreferences!.setBool(key!, value);
return await sharedPreferences!.setDouble(key!, value);
}
static Future<bool> removeData({@required String? key}) async
{
return await sharedPreferences!.remove(key!);
}
}
class HomeModel
{
bool? status;
HomeDataModel? data;
HomeModel.fromJson(Map<String, dynamic> json)
{
status = json['status'];
data = HomeDataModel.fromJson(json['data']);
}
}
class HomeDataModel
{
List<BannerModel> banners = [];
List<ProductModel> products = [];
HomeDataModel.fromJson(Map<String, dynamic> json)
{
json['banners'].forEach((element)
{
banners.add(element);
});
json['products'].forEach((element)
{
products.add(element);
});
}
}
class BannerModel
{
int? id;
String? image;
BannerModel.fromJson(Map<String, dynamic> json)
{
id = json['id'];
image = json['image'];
}
}
class ProductModel
{
int? id;
dynamic price;
dynamic oldPrice;
dynamic discount;
String? image;
String? name;
bool inFavourites = false;
bool inCart = false;
ProductModel.fromJson(Map<String, dynamic> json)
{
id = json['id'];
price = json['price'];
oldPrice = json['old_price'];
discount = json['discount'];
image = json['image'];
name = json['name'];
inFavourites = json['in_favourites'];
inCart = json['in_cart'];
}
}
After making a debug I found that the error occurs at the getHomeData method in the Cubit File, but couldn't find any Solutions.
I guess the error comes from this line:
printFullText(homeModel!.data!.banners[0].image);
Those exclamation marks there (called "non-null assertion operators") mean that you expect homeModel
not to be null and homeModel.data
not to be null. That's too much to expect, because these values come from parsing an HTTP response.
Possible solutions:
homeModel
and homeModel.data
before using them, and if they are null react properly.In all cases, remove the !
operators.