skip to Main Content

I admittedly still have poor understanding of null checks but I do understand the gist of it (I think lol). However in this case I’m quite confused why I’m getting a null check exception. I’m storing the data inside textControllers because instead of using TextFormFields, I’m using Text widget to display textController.values. The user makes changes by opening a dialog and submitting new data there. It will call setState to make the changes to the widget. Basically, the user can see the changes the made to their profile instead of having a form. It was for this reason that I choose not to use FutureBuilder because setState will recall data from the Firebase and overwrite the changes.

That’s a short summary of what I’m trying to achieve. My main issue is that I have a String? rating variable that is set a value on initState through a Future function that fetches data from Firestore. Other values are showing such as the starting_price and description. Rating seems to be the main issue for some reason. Initially, it was a integer variable and a number data type in Firestore but I changed it to String to see if the code worked. If I pass rating into a widget, it will require a null check operator since its a nullable String. It will return an null check operator used on a null value exception. It works when I pass a toString function to the variable inside Text widget but still an error when I parsed it to double for the RatingBarIndicator (flutter_rating_bar package).

I suspect it’s due to the Widget building before a value is set to rating variable but I already initialised it inside initState. How do I achieve this with or without FutureBuilder?

I removed a few lines to keep the code short but I can provide the rest if necessary.

profile_screen.dart

class ProfileScreen extends StatefulWidget {
  const ProfileScreen({super.key, required this.userId});
  final String userId;

  @override
  State<ProfileScreen> createState() => _ProfileScreenViewState();
}

class _ProfileScreenViewState extends State<ProfileScreen> {
String? rating;

@override
  void initState() {
    super.initState();
    fetchProviderData(widget.userId);
  }

Future<void> fetchProviderData(String userId) async {
    final DocumentSnapshot snapshot = await FirebaseFirestore.instance
        .collection('providers')
        .doc(userId)
        .get();

    if (snapshot.exists) {
      final data = snapshot.data() as Map<String, dynamic>?;
      if (data != null) {
        setState(() {
          startPriceController.text = data['starting_price'];
          descriptionController.text = data['description'];
          profilePicUrl = data['profile_picture'] as String;
          rating = data['rating'] as String;
          services = data['services'] as List<dynamic>;

          print(rating);
          print(startPriceController.text);
        });
      }
    }
  }

@override
  Widget build(BuildContext context) {
    print(startPriceController.text); // IT SHOWS THE CORRECT VALUES
    print(descriptionController.text);
    print(rating);
    return Scaffold(
        body: Padding(
            padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 32),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
                  Flexible(
                      child: Padding(
                          padding: const EdgeInsets.symmetric(
                              horizontal: 12, vertical: 5),
                          child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Text(rating.toString()),
                                 RatingBarIndicator(
                                   rating: double.parse(rating.toString()),
                                   itemCount: 5,
                                   itemSize: 15,
                                   itemBuilder: (context, _) => const Icon(
                                       Icons.star,
                                       color: Colors.amber),
                                 ),
                              ])))
                ]),
              ],
            )));
  }
}

Printing the values inside widget build does show it has correct values but it’s printing twice(?)

Console

I/flutter ( 4651): LANDING: PROFILE CLICKED
I/flutter ( 4651): START PRICE:
I/flutter ( 4651): DESC:
I/flutter ( 4651): RATING:
I/flutter ( 4651): START PRICE: 20.1
I/flutter ( 4651): DESC: description here
I/flutter ( 4651): RATING: 3

Stack Trace

════════ Exception caught by widgets library ═══════════════════════════════════
The following FormatException was thrown building ProfileScreen(dirty, state: _ProfileScreenViewState#060dc):
Invalid double

The relevant error-causing widget was
ProfileScreen
landing_page.dart:197
When the exception was thrown, this was the stack
#0      double.parse (dart:core-patch/double_patch.dart:111:28)
#1      _ProfileScreenViewState.build
profile_screen.dart:219
#2      StatefulElement.build
framework.dart:4992
#3      ComponentElement.performRebuild
framework.dart:4878
#4      StatefulElement.performRebuild
framework.dart:5050
#5      Element.rebuild
framework.dart:4604
#6      ComponentElement._firstBuild
framework.dart:4859
#7      StatefulElement._firstBuild
framework.dart:5041
#8      ComponentElement.mount
framework.dart:4853
...     Normal element mounting (275 frames)
#283    Element.inflateWidget
framework.dart:3863
#284    MultiChildRenderObjectElement.inflateWidget
framework.dart:6435
#285    Element.updateChild
framework.dart:3592
#286    RenderObjectElement.updateChildren
framework.dart:5964
#287    MultiChildRenderObjectElement.update
framework.dart:6460
#288    Element.updateChild
framework.dart:3570
#289    ComponentElement.performRebuild
framework.dart:4904
#290    StatefulElement.performRebuild
framework.dart:5050
#291    Element.rebuild
framework.dart:4604
#292    StatefulElement.update
framework.dart:5082
#293    Element.updateChild
framework.dart:3570
#294    ComponentElement.performRebuild
framework.dart:4904
#295    Element.rebuild
framework.dart:4604
#296    ProxyElement.update
framework.dart:5228
#297    Element.updateChild
framework.dart:3570
#298    ComponentElement.performRebuild
framework.dart:4904
#299    Element.rebuild
framework.dart:4604
#300    ProxyElement.update
framework.dart:5228
#301    _InheritedNotifierElement.update
inherited_notifier.dart:107
#302    Element.updateChild
framework.dart:3570
#303    SingleChildRenderObjectElement.update
framework.dart:6307
#304    Element.updateChild
framework.dart:3570
#305    ComponentElement.performRebuild
framework.dart:4904
#306    StatefulElement.performRebuild
framework.dart:5050
#307    Element.rebuild
framework.dart:4604
#308    StatefulElement.update
framework.dart:5082
#309    Element.updateChild
framework.dart:3570
#310    SingleChildRenderObjectElement.update
framework.dart:6307
#311    Element.updateChild
framework.dart:3570
#312    SingleChildRenderObjectElement.update
framework.dart:6307
#313    Element.updateChild
framework.dart:3570
#314    ComponentElement.performRebuild
framework.dart:4904
#315    Element.rebuild
framework.dart:4604
#316    ProxyElement.update
framework.dart:5228
#317    Element.updateChild
framework.dart:3570
#318    ComponentElement.performRebuild
framework.dart:4904
#319    StatefulElement.performRebuild
framework.dart:5050
#320    Element.rebuild
framework.dart:4604
#321    BuildOwner.buildScope
framework.dart:2667
#322    WidgetsBinding.drawFrame
binding.dart:882
#323    RendererBinding._handlePersistentFrameCallback
binding.dart:378
#324    SchedulerBinding._invokeFrameCallback
binding.dart:1175
#325    SchedulerBinding.handleDrawFrame
binding.dart:1104
#326    SchedulerBinding._handleDrawFrame
binding.dart:1015
#327    _invoke (dart:ui/hooks.dart:148:13)
#328    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#329    _drawFrame (dart:ui/hooks.dart:115:31)
════════════════════════════════════════════════════════════════════════════════

Edit: Added null value stack

Stack Trace (null value exception)

════════ Exception caught by widgets library ═══════════════════════════════════
The following _CastError was thrown building ProfileScreen(dirty, state: _ProfileScreenViewState#30924):
Null check operator used on a null value

The relevant error-causing widget was
ProfileScreen
landing_page.dart:197
When the exception was thrown, this was the stack
#0      _ProfileScreenViewState.build
profile_screen.dart:219
#1      StatefulElement.build
framework.dart:4992
#2      ComponentElement.performRebuild
framework.dart:4878
#3      StatefulElement.performRebuild
framework.dart:5050
#4      Element.rebuild
framework.dart:4604
#5      ComponentElement._firstBuild
framework.dart:4859
#6      StatefulElement._firstBuild
framework.dart:5041
#7      ComponentElement.mount
framework.dart:4853
...     Normal element mounting (275 frames)
#282    Element.inflateWidget
framework.dart:3863
#283    MultiChildRenderObjectElement.inflateWidget
framework.dart:6435
#284    Element.updateChild
framework.dart:3592
#285    RenderObjectElement.updateChildren
framework.dart:5964
#286    MultiChildRenderObjectElement.update
framework.dart:6460
#287    Element.updateChild
framework.dart:3570
#288    ComponentElement.performRebuild
framework.dart:4904
#289    StatefulElement.performRebuild
framework.dart:5050
#290    Element.rebuild
framework.dart:4604
#291    StatefulElement.update
framework.dart:5082
#292    Element.updateChild
framework.dart:3570
#293    ComponentElement.performRebuild
framework.dart:4904
#294    Element.rebuild
framework.dart:4604
#295    ProxyElement.update
framework.dart:5228
#296    Element.updateChild
framework.dart:3570
#297    ComponentElement.performRebuild
framework.dart:4904
#298    Element.rebuild
framework.dart:4604
#299    ProxyElement.update
framework.dart:5228
#300    _InheritedNotifierElement.update
inherited_notifier.dart:107
#301    Element.updateChild
framework.dart:3570
#302    SingleChildRenderObjectElement.update
framework.dart:6307
#303    Element.updateChild
framework.dart:3570
#304    ComponentElement.performRebuild
framework.dart:4904
#305    StatefulElement.performRebuild
framework.dart:5050
#306    Element.rebuild
framework.dart:4604
#307    StatefulElement.update
framework.dart:5082
#308    Element.updateChild
framework.dart:3570
#309    SingleChildRenderObjectElement.update
framework.dart:6307
#310    Element.updateChild
framework.dart:3570
#311    SingleChildRenderObjectElement.update
framework.dart:6307
#312    Element.updateChild
framework.dart:3570
#313    ComponentElement.performRebuild
framework.dart:4904
#314    Element.rebuild
framework.dart:4604
#315    ProxyElement.update
framework.dart:5228
#316    Element.updateChild
framework.dart:3570
#317    ComponentElement.performRebuild
framework.dart:4904
#318    StatefulElement.performRebuild
framework.dart:5050
#319    Element.rebuild
framework.dart:4604
#320    BuildOwner.buildScope
framework.dart:2667
#321    WidgetsBinding.drawFrame
binding.dart:882
#322    RendererBinding._handlePersistentFrameCallback
binding.dart:378
#323    SchedulerBinding._invokeFrameCallback
binding.dart:1175
#324    SchedulerBinding.handleDrawFrame
binding.dart:1104
#325    SchedulerBinding._handleDrawFrame
binding.dart:1015
#326    _invoke (dart:ui/hooks.dart:148:13)
#327    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#328    _drawFrame (dart:ui/hooks.dart:115:31)
════════════════════════════════════════════════════════════════════════════════

2

Answers


  1. Your output shows pretty clearly that the first time build is run, all your variables are not set. That is because fetchProviderData is async and not done yet, before build is called the first time.

    You can either use a FutureBuilder to display your result of an operation returning a Future. You can find an example of that here: What is a Future and how do I use it?

    Or you can simply instruct your build method to react properly to rating being null. Simplest example might be

    if(rating == null) {
      return CircularProgressIndicator();
    }
    

    but you may want a more complicated setup so it looks good with the rest of your program.

    Login or Signup to reply.
  2. You declare rating as a nullable string and inside the rating bar indicator rating is parsed into a double using,

    double.parse(rating.toString());
    

    first understand the use of toString(), toString() is used to convert any data type into string type for display textual representation, e.g.,

    int counter = 0;
    
    print(counter.toString());
    
    output: "0"
    
    String? rating;
    
    print(rating.toString());
    
    output: "null" //here rating value is null and the toString method takes null as text and converts it into a string.
    

    instead toString() with rating variable use null aware operator as below,

    rating: double.parse(rating??"0.0"),
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search