Is there a way to send a request after the user has stopped typing?

The usual way to do this in Flutter is using RxDart and its debounce() method. It allows to wait a small period before launching a specific call.

In the following full example you see it in action with a time of 1 second. In the example, a message is shown where the call to the server should be dispatched.

import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final subject = new PublishSubject<String>();

  bool isLoading = false;

  GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey();

  void _textChanged(String text) {
    if (text.isEmpty) {
      setState(() {
        isLoading = false;
      });
      return;
    }
    setState(() {
      isLoading = true;
    });
    scaffoldKey.currentState.showSnackBar(new SnackBar(
      content: new Text("Search for ${text}"),
    ));
  }

  @override
  void initState() {
    super.initState();
    subject.stream.debounce(new Duration(milliseconds: 1000)).listen(_textChanged);
  }

  @override
  void dispose() {
    subject.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: scaffoldKey,
      appBar: new AppBar(
        title: new Text("Debounce demo"),
      ),
      body: new Container(
        padding: new EdgeInsets.all(8.0),
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            new TextField(
              decoration: new InputDecoration(
                hintText: 'Type text to search',
              ),
              onChanged: (string) => (subject.add(string)),
            ),
            isLoading
                ? Padding(
                    padding: const EdgeInsets.all(20.0),
                    child: new CircularProgressIndicator(),
                  )
                : new Container(),
          ],
        ),
      ),
    );
  }
}

You can see this code in action in the following article and code by Norbert Kozsir


you can use the below code to do this:

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

class Test extends StatefulWidget {
    @override
    State<StatefulWidget> createState() {
        return _TestState();
    }
}

class _TestState extends State<StatefulWidget> {
    Timer searchOnStoppedTyping;

    _onChangeHandler(value ) {
        const duration = Duration(milliseconds:800); // set the duration that you want call search() after that.
        if (searchOnStoppedTyping != null) {
            setState(() => searchOnStoppedTyping.cancel()); // clear timer
        }
        setState(() => searchOnStoppedTyping = new Timer(duration, () => search(value)));
    }

    search(value) {
        print('hello world from search . the value is $value');
    }
    @override
    Widget build(BuildContext context) {
        return TextField(
            onChanged: _onChangeHandler,
            decoration: InputDecoration(
                hintText: 'Search ....'
                ),
            );
    }
}