Search code examples
fluttertimeouthttprequestfuture

Timeout for a Future function?


In my app when I press any button it start to show loading screen then isLoading equal to false make next page according to data from loadData function, it works when there is data but if any server or network error make app to stack in loading screen, I think I can put some timelimit to loadData for wait getData() result and actullay tried that but I couldn't get the result I want, also I tried try and catch method in Future still same result, how can I set a timelimit for await function in loadData?

The final goal I want to reach is that; when the user clicked the button my app will show loading screen and if there is data it will load next page but if there is not any data after waiting 3-4 seconds then it will show a alert dialog with a warning and a button to allow to user to go back homepage and try again.

Future<Payload> getData(String name) async{
  String myUrl = 'http://anywhere.com/query?$name';
  http.Response response = await http.get(myUrl);
  return payloadFromJson(response.body);
}

and

void loadData() async {
    payload = await getData(_name);
    isLoading = false;
    firstRun = true;
    setState(() {});
    }

catch (e) warning: enter image description here

build part or target page:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  static String routeName = "/MyHomePage";
  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey<InnerDrawerState> _innerDrawerKey = GlobalKey<InnerDrawerState>();

  bool isLoading = true;
  String _name = "";

  void loadData() async {
    payload = await getData(_name);
    isLoading = false;
    firstRun = true;
    setState(() {});
  }

  void updateName(String name) {
    setState(() {
      isLoading = true;
      this._name = name;
      loadData();
    });
  }

     @override
     void initState() { 
     super.initState();
     WidgetsBinding.instance.addPostFrameCallback((_) {
      loadData();
      WidgetsBinding.instance.addPostFrameCallback((_) =>
          _refreshIndicatorKey.currentState.show());
      getNamePreferences().then(updateName);
    });
  }

     @override
      Widget build(BuildContext context) {
        ListTile _createTile(BuildContext context, String name, IconData icon,
            Function action) {
          return ListTile(
            leading: Icon(icon),
            title: Text(name),
            onTap: () {
              Navigator.pop(context);
              action();
            },
          );
        }
        _action() {
          print('action');
        }
        return isLoading ? Center(

and for first page:

class MyFirstPage extends StatefulWidget {
  @override
  _MyFirstPageState createState() => new _MyFirstPageState();
}
class _MyFirstPageState extends State<MyFirstPage> {
  TextEditingController nameController = TextEditingController();
  bool isLoggedIn = false;
  String name = '';
  bool firstRun = true;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    autoLogIn();
  }

Future<Null> loginUser() async{...}
Future<Null> logout() async{...}
void autoLogIn() async{...}
void changeBrightness(){...}
void showChooser(){...}
void showGenre(){...}
void showSimilar(){...}


@override
  Widget build(BuildContext context) {
    return new Scaffold(

Solution

  • You can specify a timeout to your http request.

    http.Response response = await http.get(myUrl).timeout(const Duration(seconds: 10));
    

    You have to handle the TimeoutException to stop the loading indicator:

    try {
        payload = await getData(_name);
        // Remaining code 
    } on TimeoutException catch (e) {
        setState(() {
           isLoading = false;
        });
    }