Home > Back-end >  How can I set the order of execution for different future in Flutter?
How can I set the order of execution for different future in Flutter?

Time:08-27

I'm implementing a flutter project using Getx library.

My current project has a format in which the response from the backend is recombined at the front end to the ui model and show on the screen. (Because the project's d-day is very close, so I could not change backend. I should just use a existing backend response).

Meanwhile, I was writing a code that some api call futures must keep the order.

To put it briefly, I receive a survey's result list and make a string list with survey's id (it is in the survey's result object).

After that, I receive a survey list and compare it to survey's result id list.

Through these courses, I will be able to know whether the survey has been completed or not from the survey list.

To implement this action, I declared two future, and I thought that the future was guaranteed the order by executing it with wait.

But nothing is changed in my view...

Below things are my codes.

class ExampleController extends GetxController {
  final PreferenceManager _preferenceManager =
      Get.find(tag: (PreferenceManager).toString());

  /// ------------> related to survey values
  final RxList<SurveyListUiModel> _rxSurveyListUiModelList = RxList.empty();

  List<SurveyListUiModel> get surveyListUiModelList =>
      _rxSurveyListUiModelList.toList();

  final List<String> _surveyResultIdList = [];

  void getSurveyConfigListWithSurveyResult() async{
    Future<String> surveyResultListFuture =
        _preferenceManager.getString('survey_result_list');

    callDataService(
      surveyResultListFuture,
      onSuccess: _handleSurveyResultListResponseSuccess,
    );

    Future<String> surveyListFuture =
        _preferenceManager.getString('survey_list');

    await callDataService(
      surveyConfigListFuture,
      onSuccess: _handleSurveyListResponseSuccess,
    );

    setListLoading(false);
  }

  void _handleSurveyResultListResponseSuccess(String response) {
    List<dynamic> list = jsonDecode(response) as List<dynamic>;

    for (var element in list) {
      SurveyConfigResponse surveyConfigResponse = SurveyConfigResponse.fromJson(
          element['survey_config'] as Map<String, dynamic>);

      _surveyResultIdList.add(surveyConfigResponse.id);
    }
  }

  void _handleSurveyListResponseSuccess(String response) {
    List<dynamic> list = jsonDecode(response) as List<dynamic>;

    for (var element in list) {
      SurveyConfigResponse surveyConfigResponse =
          SurveyConfigResponse.fromJson(element as Map<String, dynamic>);

      surveyListUiModelList.add(SurveyListUiModel(
        surveyConfigId: surveyConfigResponse.id,
        surveyConfigTitle: surveyConfigResponse.title,
        isDiagnosed: _surveyResultIdList.contains(surveyConfigResponse.id),
      ));
      _rxSurveyListUiModelList.refresh();
    }
  }

  /// ------------> related to survey values

  @override
  void onInit() {
    getSurveyConfigListWithSurveyResult();
    super.onInit();
  }
}
// callDataService method
dynamic callDataService<T>(
    Future<T> future, {
    Function(Exception exception)? one rror,
    Function(T response)? onSuccess,
    Function? onStart,
    Function? onComplete,
  }) async {
    Exception? _exception;

    onStart == null ? showLoading() : onStart();

    try {
      final T response = await future;

      if (onSuccess != null) onSuccess(response);

      onComplete == null ? hideLoading() : onComplete();

      return response;
    } on ServiceUnavailableException catch (exception) {
      _exception = exception;
      showErrorMessage(exception.message);
    } on UnauthorizedException catch (exception) {
      _exception = exception;
      showErrorMessage(exception.message);
    } on TimeoutException catch (exception) {
      _exception = exception;
      showErrorMessage(exception.message);
    } on NetworkException catch (exception) {
      _exception = exception;
      showErrorMessage(exception.message);
    } on JsonFormatException catch (exception) {
      _exception = exception;
      showErrorMessage(exception.message);
    } on NotFoundException catch (exception) {
      _exception = exception;
      showErrorMessage(exception.message);
    } on ApiException catch (exception) {
      _exception = exception;
    } on AppException catch (exception) {
      _exception = exception;
      showErrorMessage(exception.message);
    } catch (error) {
      _exception = AppException(message: "$error");
      logger.e("Controller>>>>>> error $error");
    }

    if (onError != null) one rror(_exception);

    onComplete == null ? hideLoading() : onComplete();
  }
// example view
class ExampleView extends GetView<ExampleController> {
  @override
  Widget body(BuildContext context) {
    return Obx(() => Text(controller.surveyListUiModelList.length.toString()));
  }
}

What is the missing point in my codes..?


Edit 1

With obove code, the lists in the _handle~~~Success method has a right value.

CodePudding user response:

A bit tricky to follow your code, but I think you should be awaiting the first call to callDataService(...)

I.e. this:

callDataService(
  surveyLifeResultListFuture,
  onSuccess: _handleSurveyResultListResponseSuccess,
);

should be:

await callDataService(
  surveyLifeResultListFuture,
  onSuccess: _handleSurveyResultListResponseSuccess,
);

CodePudding user response:

Oh It's my mistake. The method callDataService is an already synchronized method...

So I did not have to consider asynchronization.

The order in which the code was written was applied in the order of execution.

A real problem was RxList.

In my question code, I writed a getter method of RxList like this.

List<SurveyListUiModel> get surveyListUiModelList => _rxSurveyListUiModelList.toList();

The toList() method is just extracting a Growable List from RxList.

it's code is here.

List<E> toList({bool growable = true}) {
    if (this.isEmpty) return List<E>.empty(growable: growable);
    var first = this[0];
    var result = List<E>.filled(this.length, first, growable: growable);
    for (int i = 1; i < this.length; i  ) {
      result[i] = this[i];
    }
    return result;
}

And, with that extracted list(copy the past state of RxList), I tried adding new items...

So, the obx widget in exampleView that is observing RxList did not response the past extracted list.

To solve this question, I changed my add items code with RxList keeping others in same.


before

void _handleSurveyConfigListResponseSuccess(String response) {
    List<dynamic> list = jsonDecode(response) as List<dynamic>;

    for (var element in list) {
      SurveyConfigResponse surveyConfigResponse =
          SurveyConfigResponse.fromJson(element as Map<String, dynamic>);

      surveyListUiModelList.add(SurveyListUiModel(
        surveyConfigId: surveyConfigResponse.id,
        surveyConfigTitle: surveyConfigResponse.title,
        isDiagnosed: _surveyResultIdList.contains(surveyConfigResponse.id),
      ));
    }

    _rxSurveyListUiModelList.refresh();
  }

after

void _handleSurveyConfigListResponseSuccess(String response) {
    List<dynamic> list = jsonDecode(response) as List<dynamic>;

    for (var element in list) {
      SurveyConfigResponse surveyConfigResponse =
          SurveyConfigResponse.fromJson(element as Map<String, dynamic>);

      _rxSurveyListUiModelList.add(SurveyListUiModel(
        surveyConfigId: surveyConfigResponse.id,
        surveyConfigTitle: surveyConfigResponse.title,
        isDiagnosed: _surveyResultIdList.contains(surveyConfigResponse.id),
      ));
    }

    _rxSurveyListUiModelList.refresh();
  }
  • Related