简体   繁体   中英

How to catch exception in a callback function in Dart (Flutter)?

I'm using WebSocket variable in my MyWebSocket class. For listen i give a callback function as parameter. If this callback function throws an exception in calling class MyChat , then i can not catch that exception anywhere.

My simplified code is:

class MyWebSocket {
  WebSocket _ws;
  ...
  // initialized in controller: _ws = WebSocket.connect(_some_url_);
  // everything works (connect, listen)
  ...
  void listen({void Function(dynamic) myOnListen}) {
    try {
      _ws.listen(myOnListen)
        .onError((e) => print("MyWebSocket in MyChat.onError: $e"));
    } catch (e) {
      print("Catched in MyWebSocket: $e");
    }
  }
}


class MyChat {
  MyWebSocket _chatWs = MyWebSocket();
  ...
  void initWS() {
    try {
      _chatWs.listen(myOnListen: processMsg);
    } catch (e) {
      print("Catched in MyChat: $e");
    }
  }

  void processMsg(dynamic msg) {
    if(_some_stuff_like_invalid_msg_or_not_logged_in_...)
      throw Exception("There is my Exception");
  }
}

I have built try-catch in every possible place to catch exceptions - no success, i got only unhandled exception:

E/flutter: [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Exception: There is my Exception

E/flutter: #0 MyChat.processMsg

Beware that you cannot use the passed listener as a key for later removal. For that you can pass the new listener created in MyWebSocket class when listen() is called, then use this key to remove the listener.

class MyWebSocket {
  WebSocket _ws;
  void listen({void Function(dynamic) myOnListen, void Function(Error) onError}) {
    try {
      _ws.listen((){
        try {
          myOnListen({"label": "DATA"});
        } catch (e) {
          if(onError is Function)
          onError(e)
        }
      })
        .onError(onError);
    } catch (e) {
      print("Catched in MyWebSocket: $e");
    }
  }
}


class MyChat {
  MyWebSocket _chatWs = MyWebSocket();
  void initWS() {
    try {
      _chatWs.listen(myOnListen: processMsg, onError: (Error error){
        print("ERROR: "+error.toString());
      });
    } catch (e) {
      print("Catched in MyChat: $e");
    }
  }

  void processMsg(dynamic msg) {
    if(_some_stuff_like_invalid_msg_or_not_logged_in_...)
      throw Exception("There is my Exception");
  }
}

You need to handle it inside your processMsg
If you analyze carefully the execution of your code the _ws.listent register a listener for when you receive a message and that will happen in the FUTURE, but you don't get an error WHILE you are REGISTERING your listener that's why that doesn't work the way you expect.
processMsg will do something in the future, it will throw an error and it's at the end of the pipeline.
You are simulating an exception and nothing is handling it, it happens in a different stack frame, in the future.
The void listen({void Function(dynamic) myOnListen}) function execution is long gone when you receive and you precessMsg .
Alternatively you could do:

Function tryCatchHOF(Function cb) {
  decorated(dynamic param) {
    try {
      cb(param);
    } catch (e) {
      print("$e");
    }
  }

  ;
  return decorated;
}

void processMsg(dynamic msg) {
  if (true) throw Exception("There is my Exception");
}

var processMsgWithTryCatch = tryCatchHOF(processMsg);
  processMsgWithTryCatch('');

and then pass processMsgWithTryCatch down to your listener if you don't want to handle inside processMsg

I hope that make sense

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM