1

I'm developing an app (using Flutter) that has a model that contains most of the business logic, and a view that displays the user interface. The model can call notifyListeners to inform the view that some data in the model has changed, and the UI should be rebuilt.

I currently keep track of the status of some pieces of data in the model using flags that indicate wether the data is in an OK, ERROR or LOADING state.

Simplified example:

class ContactModel{

  int contactListState = OK; // OK/ERROR/LOADING are int constants
  List<String> contacts = [];


  Future<void> fetchContactList(){
    contactListState = LOADING;
    notifyListeners();
    
    bool success = false;
    // Make some API call, which may or may not succeed

    contactListState = success ? OK : ERROR;
    notifyListeners();     
  }
}

The UI would display a spinner when contactListState==LOADING or an error indicator when contactListState==ERROR.

This all works fine, BUT... now I want to display more fine grained error messages to the user about what exactly went wrong. There are a few possibilities:

  1. return Future<String> instead of Future<void>, returning a user friendly error message.
  2. store the last error message just like the state, i.e. add the member String contactListErrorMessage.
  3. throw an exception in the model, possibly containing a user friendly error message, catch it where I made the call and display the error message to the user.

Each have their pros and cons:

  1. Simple and easy to understand, but becomes more complex if I actually wanted to return something useful from the method on success.
  2. Kind of makes sense in that it is similar to the existing flag contactListState. But how long should an error message "live"? Who is responsible for clearing it? Not to mention the amount of members needed as the model grows.
  3. Makes for easier logic in the model, but probably more complex logic in the view instead. For example, one would need to add a stateful variable to store the error message in the view, so it doesn't disappear on the next UI rebuild.

What is the most common way to solve this kind of error message handling? Are there any additional pros/cons that make any of the options a clear winner?

2 Answers 2

2

There is a fundamental decision here that has locked you into this design. Your model is always available and known to everything. This has forced you to make your model mutable.

Instead, you could design a system where most or your models are immutable response models that only exist once fully “loaded”. These models data would never be out of sync with their state flag, making them thread safe, easier to read, and easier to debug.

Models that are still loading would be safe from being read because nothing that reads will know they exist yet.

Now errors would still happen but since you control what is called when loading is finished you can call something that specializes in that result/error. This is usually better than throwing every possible result at one target. This way keeps the targets simple.

Not that your way won’t work. It just comes with problems you may wish to avoid.

0

I think the generally designed error handling within Flutter is to use try/catch statements. I return a String so that I can return the error to the user in a dialog if it's needed, print to console, otherwise. Good for really quick debugging and user experience. I return "Success" otherwise. I do this with my Cloud Functions, Firebase writes, etc.

Validators for forms.

So, I think a Future would be the standard. But maybe that was just how I was taught, and I gravitated to it. There always seems to be a next level or argument otherwise.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.