Sobes.tech
Middle

What is a Completer in Dart and how can it be used in Flutter development?

sobes.tech AI

Answer from AI

Completer is a class in the dart:async library that allows creating a Future and completing it later with a value or an error. It is useful when an asynchronous operation does not return a Future directly but can be notified of its completion.

import 'dart:async';

void main() async {
  final completer = Completer<String>(); // Create a Completer for Future<String>

  // Simulate an asynchronous operation
  Future.delayed(Duration(seconds: 2), () {
    // Complete the Future with a successful value
    completer.complete("Operation completed successfully!");
    // completer.completeError(StateError("Something went wrong!")); // Or with an error
  });

  print("Waiting for operation to complete...");

  try {
    // Get the Future from the Completer and wait for it to complete
    final result = await completer.future;
    print("Result: $result");
  } catch (e) {
    print("An error occurred: $e");
  }
}

In Flutter, Completer is often used for:

  • Integration with native APIs: When native code calls a callback upon operation completion, Completer can be used to convert this into a Future in Dart.
  • Implementing custom asynchronous operations: When you need to create an async function that does not use existing Future-returning APIs.
  • Communication between isolates: To signal the completion of work in another isolate.

Example of usage in Flutter with a native API (hypothetical):

import 'dart:async';
import 'package:flutter/services.dart';

class NativeService {
  static const platform = MethodChannel('com.example/native_service');

  Future<String> performNativeOperation() async {
    final completer = Completer<String>();

    try {
      final result = await platform.invokeMethod('startOperation');

      // It is assumed that native code will call 'operationCompleted'
      // with the result or error, and we listen for these calls.
      platform.setMethodCallHandler((call) async {
        if (call.method == 'operationCompleted') {
          if (call.arguments is String) {
            completer.complete(call.arguments as String);
          } else if (call.arguments is PlatformException) {
            completer.completeError(call.arguments as PlatformException);
          } else {
            completer.completeError(StateError("Unknown native operation result"));
          }
          // Remove the handler if no longer needed
          platform.setMethodCallHandler(null);
        }
        return true; // Indicate that the call was handled
      });

    } on PlatformException catch (e) {
      completer.completeError(e);
    }

    return completer.future; // Return the Future that will be completed later
  }
}

// In a widget or elsewhere:
// final service = NativeService();
// try {
//   final nativeResult = await service.performNativeOperation();
//   print("Native result: $nativeResult");
// } catch (e) {
//   print("Native operation error: $e");
// }