skip to Main Content

I am new to Flutter and Firebase. I am stuck on how to handle exceptions. For example, if there’s no internet or if something went wrong, I want to show a Snackbar displaying that error message. What I am trying to do is:

1. get the user to input some data and pictures
2. Upload that picture to Firebase Storage and retrieve the URL
3. Upload data input by user and URL to Firestore

4.Catch any errors and display on a Snackbar

To begin,
When I click on the save button it will call this function:

void _saveItem() async {

    if (_formKey.currentState!.validate()) {
      setState(() {
        _isSaving = true;
      });
      _formKey.currentState!.save();
      final urlLink = await uploadImage(_selectedImage);

      createListing(
        itemName: _itemName!,
        urlLink: urlLink!,
        mainCat: _chosenMainCategory!,
        subCat: _chosenSubCategory!,
        dietaryInfo: _chosenDietaryOption!,
        addInfo: _additionalInfo!,
        expDate: _chosenDate!,
        lat: _lat!,
        lng: _lng!,
        address: _address!,
      );
      Navigator.pop(context);
    }
  }

Which will then call uploadImage to retrieve the image URL:

Future<String> uploadImage(File file) async {
    String fileName = DateTime.now().millisecondsSinceEpoch.toString();
    firebase_storage.Reference ref = firebase_storage.FirebaseStorage.instance
        .ref()
        .child('listingImages/$fileName');

    await ref.putFile(file);

    String imageUrl = await ref.getDownloadURL();
    return imageUrl;
  }

Then it will call createListing to upload the document onto Firestore:

Future<void> createListing({
    required String itemName,
    required String urlLink,
    required String mainCat,
    required String subCat,
    required String dietaryInfo,
    required String addInfo,
    required DateTime expDate,
    required double lat,
    required double lng,
    required String address,
  }) async {
    final docListing = FirebaseFirestore.instance.collection('Listings').doc();

    final user = FirebaseAuth.instance.currentUser!;

    final listing = Listing(
      id: docListing.id,
      itemName: itemName,
      image: urlLink,
      mainCategory: mainCat,
      subCategory: subCat,
      dietaryNeeds: dietaryInfo,
      additionalNotes: addInfo,
      expiryDate: expDate,
      lat: lat,
      lng: lng,
      address: address,
      isAvailable: true,
      userId: user.email.toString(),
      userName: user.displayName.toString(),
    );

    final json = listing.toJson();
    await docListing.set(json);
  }

I don’t know where or how I am supposed to handle errors or exceptions.

I have tried using try catch on everything that has ‘await’ but it doesnt seem to timeout and the snackbar was never shown on screen.

This is my utils class i use for displaying errors on snackbars.

class Utils {
  static final messengerKey = GlobalKey<ScaffoldMessengerState>();

  static showSnackBar(String? text) {
    if (text == null) return;

    final snackBar = SnackBar(content: Text(text), backgroundColor: Colors.red);

    messengerKey.currentState!
      ..removeCurrentSnackBar()
      ..showSnackBar(snackBar);
  }
}

The way i use it to display an error e on screen:

Utils.showSnackBar(e.message);

Would like to get some comments on my edit, i am not sure whether this would suffice just by adding a try catch when calling saveItem function:

void _saveItem() async {
    if (_selectedImage == null) {
      showDialog(
        context: context,
        builder: (ctx) => AlertDialog(
          title: const Text(
            'Picture missing',
            textAlign: TextAlign.center,
          ),
          content: const SizedBox(
            height: 16,
            width: 32,
            child: Center(
              child: Text('Add a picture'),
            ),
          ),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.pop(ctx);
              },
              child: const Text('ok'),
            ),
          ],
        ),
      );
      return;
    }
    if (_address == null) {
      showDialog(
        context: context,
        builder: (ctx) => AlertDialog(
          title: const Text(
            'Address missing',
            textAlign: TextAlign.center,
          ),
          content: const SizedBox(
            height: 16,
            width: 32,
            child: Center(
              child: Text('Click on get address'),
            ),
          ),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.pop(ctx);
              },
              child: const Text('ok'),
            ),
          ],
        ),
      );
      return;
    }
    if (_formKey.currentState!.validate()) {
      setState(() {
        _isSaving = true;
      });
      _formKey.currentState!.save();
      try {
        final urlLink = await uploadImage(_selectedImage);

        createListing(
          itemName: _itemName!,
          urlLink: urlLink!,
          mainCat: _chosenMainCategory!,
          subCat: _chosenSubCategory!,
          dietaryInfo: _chosenDietaryOption!,
          addInfo: _additionalInfo!,
          expDate: _chosenDate!,
          lat: _lat!,
          lng: _lng!,
          address: _address!,
        );
      } catch (e) {
        Utils.showSnackBar('error: $e');
      }
      Navigator.pop(context);
    }
  }

2

Answers


  1. Usually, when we are calling something to the network add a try-catch clause to catch any errors,
    also you can check your network connection using this package https://pub.dev/packages/connectivity_plus

    in your case, you can add it here

     Future<String> checkPasswordChanged(BuildContext context) async {
        bool hasConnection = await NetworkConn.isInternet();
        String imageUrl ="";
        if (hasConnection) {
          try {
            String fileName = DateTime.now().millisecondsSinceEpoch.toString();
            firebase_storage.Reference ref = firebase_storage
                .FirebaseStorage.instance
                .ref()
                .child('listingImages/$fileName');
    
            await ref.putFile(file);
    
            imageUrl = await ref.getDownloadURL();
          } catch (e) {
            print('Error fetching document: $e');
          }
        } else {
          print("Please Connect to Internet");
        }
        return  imageUrl;
      }
    
    Login or Signup to reply.
  2. For example, when the internet connection was lost and I try to upload to Firebase Storage and Firestore, I expect the error/ exception to be caught.

    The loss of the internet will never rise an exception. And this is because the Firebase products you work with are designed to work offline. So if you lose connectivity, your app will continue to work.

    Instead, it just kept attempting to upload and I waited at least 10 minutes and it still did not timeout.

    That’s the expected behavior. The Firebase SDK will try to reconnect until the device regains connectivity.

    So if you need to take some action only when the device is connected to the internet, then you have to check that yourself.

    Please note that @MrShakila’s solution will help only to know if the device is connected to a network. However, you can be connected to a network, to a WiFi network, for example, that doesn’t have an internet connection. So you have to check two things, if you’re connected to a network and if the internet is working properly. This means that you can try to ping a server in your application code, and see if you get a response. This can be done by pinging Google servers using:

    /system/bin/ping -c 1 8.8.8.8
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search