0

Here is my flutter code where I try to use FutureBuilder but encounter problems due to the null protection in Dart.

class AbcClass extends StatefulWidget {
  @override
  _AbcClassState createState() =>
      _AbcClassState();
}

class _AbcClassState
    extends State<AbcClass>
    with AutomaticKeepAliveClientMixin {
  _AbcClassState();

  Future? _purchaserInfoSnapshot;

  @override
  void initState() {
    _purchaserInfoSnapshot = setPurchaserInfo();
    super.initState();
  }

  setPurchaserInfo() async {
    PurchaserInfo purchaserInfo = await getPurchaserInfo();

    Purchases.addPurchaserInfoUpdateListener((purchaserInfo) async {
      if (this.mounted) {
        setState(() {
          _purchaserInfoSnapshot = Future.value(purchaserInfo);
        });
      }
    });

    return purchaserInfo;
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    
    return FutureBuilder(
        future: _purchaserInfoSnapshot,
        builder: (context, snapshot) {
          if (!snapshot.hasData ||
              snapshot.data == null ||
              snapshot.connectionState != ConnectionState.done) {
            return Center(
                child: Text(
              'Connecting...',
              style: Theme.of(context).textTheme.headline3,
            ));
          } else {
            if (snapshot.data.entitlements.active.isNotEmpty) {
            
              return Scaffold(...);
            } else {
              return MakePurchase();
            }
          }
        });
  }
}

The part that creates the problem is the following:

if (snapshot.data.entitlements.active.isNotEmpty)

And the error message:

The property 'entitlements' can't be unconditionally accessed because the receiver can be 'null'.
Try making the access conditional (using '?.') or adding a null check to the target ('!').

I tried updating it as the following:

else if (snapshot.data!.entitlements.active.isNotEmpty)

... but it did not help.

Any ideas on how I am supposed to deal with it?

Note: I did not paste the entire code as it involves a lot of opther logic that is not relevant to this question. I hope the pseudo code above will still help.

edn
  • 1,981
  • 3
  • 26
  • 56
  • try with this `if (snapshot.data?.entitlements?.active.isNotEmpty)` – Jahidul Islam Oct 27 '21 at 11:02
  • @JahidulIslam It unfortunately did not help – edn Oct 27 '21 at 11:03
  • @JahidulIslam No, it gives the error "The getter 'entitlements' isn't defined for the type 'Object'. Try importing the library that defines 'entitlements', correcting the name to the name of an existing getter, or defining a getter or field named 'entitlements'." But I get exactly the same (new) error when I try fix that I mentioned in my post as well. But if I write ´(snapshot.data as PurchaserInfo) .entitlements .active .isNotEmpty)´ the error disappears completely. Why..? – edn Oct 27 '21 at 11:15
  • 1
    @edn This is because the field `entitlements` does not exist on the `snapshot` class. The data for a `snapshot` is placed in `snapshot.data` field. Subsequently after you cast the `snapshot.data` field to `PurchaseInfo` the `entitlement` field is available – Rohan Thacker Oct 27 '21 at 11:20
  • 1
    @edn **Note:** This is a good place to add a type, then you can avoid the cast by adding the type to `FutureBuilder` Widget. For example `FutureBuilder` – Rohan Thacker Oct 27 '21 at 11:25

1 Answers1

1

You've probably enabled null-safety in your project. Now the compiler won't let you compile code that it is not sure that won't throw an Null Exception error (like trying to access a property of a nullable variable without checking if its not null first)

You can either mark it with the bang ! operator and tell the compiler this variable will never be null, which may not be true, so be aware when using it.

Or you could check if the variable is not null before accessing its properties or trying to call methods on it.

Try this:

final active = snapshot.data?.entitlements?.active;
if (active != null && active.isNotEmpty)

I've also seen that you tried to check if snapshot.data was not null first. But remember that for the flow-analysis to work, you have to assign the variable you're trying to test to a local final variable.

Like:

final data = snapshot.data;
if (!snapshot.hasData || data == null || snapshot.connectionState != ConnectionState.done) {
  return ...
pedro pimont
  • 2,764
  • 1
  • 11
  • 24
  • Thank you for great explanation! I changed my min SDK from 2.7.0 to 2.12.0 and I have got hundreds of errors to fix all of a sudden.. Yes, a bit frustrating.. .:) – edn Oct 27 '21 at 11:34
  • 2
    Haha, I've been there too. This [article](https://dart.dev/null-safety/understanding-null-safety) by one of the members of the Dart Team helped me a lot. A little long but worth checking out if you're interested. – pedro pimont Oct 27 '21 at 11:37