Uncategorized

What is Dart Completer?

Dart Completer() is another type of Future. With a Completer we can create our own Future.

If you are dealing with Flutter app and Dart, most of the time you don’t need to create your own Future. Cuz most of the flutter packages bring on their own Future.

If you create your own API, and if the API doesn’t return the response as Future, in that case we need to create and use our own Future using a Completer().

Let’s see a simple example first

import 'dart:async';

void main()async{
  print(await myData());
  print("new test data");
}

Future<int> myData(){
  Completer<int> c =  Completer<int>();
  for(int i=0; i<100000000; i++){
    if(i==847594){
      c.complete(i);
      print("ye");
      break;
    }
  }

  return c.future;
  
}

Let’s see an example

import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:get/get.dart';
class WebViewPage extends StatefulWidget {
  const WebViewPage({Key? key}) : super(key: key);

  @override
  _WebViewPageState createState() => _WebViewPageState();
}

class _WebViewPageState extends State<WebViewPage> {
  late String selectedUrl;
  double value = 0.0;
  bool _canRedirect = true;
  bool _isLoading = true;
  final Completer<WebViewController> _controller = Completer<WebViewController>();
  late WebViewController controllerGlobal;

  @override
  void initState() {
    super.initState();
    //selectedUrl = '${AppConstants.BASE_URL}/payment-mobile?customer_id=${widget.orderModel.userId}&order_id=${widget.orderModel.id}';
    selectedUrl="https://learndart.net";
    //if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
  }
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () => _exitApp(context),
      child: Scaffold(
        backgroundColor: Theme.of(context).primaryColor,
        appBar: AppBar(
          title: Text("Webview"),
          leading: IconButton(icon:Icon(Icons.arrow_back_ios), onPressed: () { _exitApp(context); },),
        ),
        body: Center(
          child: Container(
            width: double.maxFinite,
            child: Stack(
              children: [
                WebView(
                  javascriptMode: JavascriptMode.unrestricted,
                  initialUrl: selectedUrl,
                  gestureNavigationEnabled: true,
                  userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_3 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13E233 Safari/601.1',
                  onWebViewCreated: (WebViewController webViewController) {
                    _controller.future.then((value) => controllerGlobal = value);
                    _controller.complete(webViewController);
                  },
                  onPageStarted: (String url) {
                    print('Page started loading: $url');
                    setState(() {
                      _isLoading = true;
                    });
                    _redirect(url);
                  },
                  onPageFinished: (String url) {
                    print('Page finished loading: $url');
                    setState(() {
                      _isLoading = false;
                    });
                    _redirect(url);
                  },
                ),
                _isLoading ? Center(
                  child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation<Color>(Theme.of(context).primaryColor)),
                ) : SizedBox.shrink(),
              ],
            ),
          ),
        ),
      ),
    );
  }

  void _redirect(String url) {
    if(_canRedirect) {
      bool _isSuccess = url.contains('success') && url.contains("https://learndart.net");
      bool _isFailed = url.contains('fail') && url.contains("https://learndart.net");
      bool _isCancel = url.contains('cancel') && url.contains("https://learndart.net");
      if (_isSuccess || _isFailed || _isCancel) {
        _canRedirect = false;
      }
      if (_isSuccess) {
        Get.to(()=>Container(child: Center(child:Text("Success")),));
      } else if (_isFailed || _isCancel) {
        Get.to(()=>Container(child: Center(child:Text("Failed")),));
      }
    }
  }

  Future<bool> _exitApp(BuildContext context) async {
    if (await controllerGlobal.canGoBack()) {
      controllerGlobal.goBack();
      return Future.value(false);
    } else {
       Get.snackbar("Test", "Test webview");
       return true;
    }
  }
}

This webview doesn’t return a Future. But we need to wait for the result to be returned and then use the callback function to redirect.

We can not use await and async here since, webview doesn’t return future response like that.

For this we need to use Completer() and wait for the response, once the response is received we can use the callback function _redirect.

Another example of dart completer

import 'dart:async';
import 'package:tutorial/models.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

final ThemeData _themeData = new ThemeData(
  primaryColor: Colors.blue,
);

/// Root MaterialApp
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    var _routes = <String, WidgetBuilder>{
      "/todos": (BuildContext context) => new TodosPage(),
      // add another page,
    };
    return new MaterialApp(
      title: "My App",
      theme: _themeData,
      home: new HomePage(),
      routes: _routes,
    );
  }
}

/// place: "/"
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text("My Home Page")),
      body: new RaisedButton(
        child: new Text("My Todos"),
        onPressed: _onPressed,
      ),
    );
  }

  void _onPressed() {
    Navigator.of(context).pushNamed("/todos");
  }
}


/// place: "/todos"
class TodosPage extends StatefulWidget {
  @override
  _TodosPageState createState() => new _TodosPageState();
}

class _TodosPageState extends State<TodosPage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text("My Todos")),
      body: new RefreshIndicator(
        child: new ListView.builder(itemBuilder: _itemBuilder),
        onRefresh: _onRefresh,
      ),
    );
  }

  Future<Null> _onRefresh() {
    Completer<Null> completer = new Completer<Null>();
    Timer timer = new Timer(new Duration(seconds: 3), () {
      completer.complete();
    });
    return completer.future;
  }

  Widget _itemBuilder(BuildContext context, int index) {
    Todo todo = getTodo(index);
    return new TodoItemWidget(todo: todo);
  }

  Todo getTodo(int index) {
    return new Todo(false, "Todo $index");
  }
}

class TodoItemWidget extends StatefulWidget {
  TodoItemWidget({Key key, this.todo}) : super(key: key);

  final Todo todo;

  @override
  _TodoItemWidgetState createState() => new _TodoItemWidgetState();
}

class _TodoItemWidgetState extends State<TodoItemWidget> {
  @override
  Widget build(BuildContext context) {
    return new ListTile(
      leading: new Text("-"),
      title: new Text(widget.todo.name),
      onTap: _onTap,
    );
  }

  void _onTap() {
    Route route = new MaterialPageRoute(
      settings: new RouteSettings(name: "/todos/todo"),
      builder: (BuildContext context) => new TodoPage(todo: widget.todo),
    );
    Navigator.of(context).push(route);
  }
}

/// place: "/todos/todo"
class TodoPage extends StatefulWidget {
  TodoPage({Key key, this.todo}) : super(key: key);

  final Todo todo;

  @override
  _TodoPageState createState() => new _TodoPageState();
}

class _TodoPageState extends State<TodoPage> {
  @override
  Widget build(BuildContext context) {
    var _children = <Widget>[
      new Text("finished: " + widget.todo.finished.toString()),
      new Text("name: " + widget.todo.name),
    ];
    return new Scaffold(
      appBar: new AppBar(title: new Text("My Todo")),
      body: new Column(
        children: _children,
      ),
    );
  }
}
class Todo{
  bool finished;
  String name;

  Todo(this.finished, this.name);
}

Have any Question or Comment?

Leave a Reply

Your email address will not be published. Required fields are marked *