Home > Software design >  How to convert event.toString() to Map<String, dynamic> in Flutter
How to convert event.toString() to Map<String, dynamic> in Flutter

Time:01-04

I used the flutter_callkit_incoming package for incoming calls, and everything works and I want to cast/convert event.toString() to Map so that I can extract a map value of body and extra.

When run this code print(event.toString()), it outputs like this below:

{ event: com.hiennv.flutter_callkit_incoming.ACTION_CALL_ACCEPT, body: {id: b9be7c0a-1c2a-46e9-ba47-e66e0e2c96ee, nameCaller: Leslie Joe, avatar: http://192.168.43.196:3000/images/1641224008963_image_picker1623631765702357491.jpg, number: 233507300523, type: 0, duration: 30000, extra: {caller: 233541395590, callee: 233507300523, callerImage: 1641224008963_image_picker1623631765702357491.jpg, calleeName: Leslie Joe, uuid: b9be7c0a-1c2a-46e9-ba47-e66e0e2c96ee, callType: calling, callerName: Woo Bear}, android: {isCustomNotification: true, ringtonePath: ringtone_default, backgroundColor: #0D1117, backgroundUrl: , actionColor: #0D1117}} }

final encodedData = json.encode(event.toString());
final decodedData = json.decode(encodedData);
final data = decodedData["body"];
final extraData = decodedData["body"]["extra"];
print(data);
print(extraData);

But it gave me errors

E/flutter (16521): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
E/flutter (16521): #0      _MainScreenState.listenerEvent.<anonymous closure>
package:sharpcall/…/screens/main_screen.dart:166
E/flutter (16521): #1      _rootRunUnary (dart:async/zone.dart:1434:47)
E/flutter (16521): #2      _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (16521): #3      _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (16521): #4      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (16521): #5      _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter (16521): #6      _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
E/flutter (16521): #7      _MapStream._handleData (dart:async/stream_pipe.dart:218:10)
E/flutter (16521): #8      _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
E/flutter (16521): #9      _rootRunUnary (dart:async/zone.dart:1434:47)
E/flutter (16521): #10     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (16521): #11     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (16521): #12     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (16521): #13     _DelayedData.perform (dart:async/stream_impl.dart:591:14)
E/flutter (16521): #14     _StreamImplEvents.handleNext (dart:async/stream_impl.dart:706:11)
E/flutter (16521): #15     _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:663:7)
E/flutter (16521): #16     _rootRun (dart:async/zone.dart:1418:47)
E/flutter (16521): #17     _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter (16521): #18     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter (16521): #19     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter (16521): #20     _rootRun (dart:async/zone.dart:1426:13)
E/flutter (16521): #21     _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter (16521): #22     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter (16521): #23     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter (16521): #24     _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
E/flutter (16521): #25     _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)

I need your help on how to convert it to a map correctly. Please check the package's example here Thanks.

CodePudding user response:

This is the json format of your event.toString() output

{
  "event": "com.hiennv.flutter_callkit_incoming.ACTION_CALL_ACCEPT",
  "body": {
    "id": "b9be7c0a-1c2a-46e9-ba47-e66e0e2c96ee",
    "nameCaller": "Leslie Joe",
    "avatar": "http://192.168.43.196:3000/images/1641224008963_image_picker1623631765702357491.jpg",
    "number": 233507300523,
    "type": 0,
    "duration": 30000,
    "extra": {
      "caller": "233541395590",
      "callee": "233507300523",
      "callerImage": "1641224008963_image_picker1623631765702357491.jpg",
      "calleeName": "Leslie Joe",
      "uuid": "b9be7c0a-1c2a-46e9-ba47-e66e0e2c96ee",
      "callType": "calling",
      "callerName": "Woo Bear"
    },
    "android": {
      "isCustomNotification": true,
      "ringtonePath": "ringtone_default",
      "backgroundColor": "#0D1117",
      "backgroundUrl": "",
      "actionColor": "#0D1117"
    }
  }
}

You can use an online tool to create classes with toMap() & fromMap() or toJson() & fromJson() methods that you can use to produce models of your objects

An example tool is https://app.quicktype.io/ (no null-safety) or https://www.webinovers.com/web-tools/json-to-dart-convertor (null-safety)

For me I like to write my own classes to have control over default values and some more functionalities. So here are the classes I would write to convert your json output

Event eventFromMap(String str) => Event.fromMap(json.decode(str));

class Event {
  Event({
    this.event,
    this.body,
  });

  String? event;
  Body? body;

  factory Event.fromMap(Map<String, dynamic> json) => Event(
    event: json["event"],
    body: json["body"] == null ? null : Body.fromMap(json["body"]),
  );
}

class Body {
  Body({
    this.id,
    this.nameCaller,
    this.avatar,
    this.number,
    this.type,
    this.duration,
    this.extra,
    this.android,
  });

  String? id;
  String? nameCaller;
  String? avatar;
  int? number;
  int? type;
  int? duration;
  Extra? extra;
  Android? android;

  factory Body.fromMap(Map<String, dynamic> json) => Body(
    id: json["id"],
    nameCaller: json["nameCaller"],
    avatar: json["avatar"],
    number: json["number"],
    type: json["type"],
    duration: json["duration"],
    extra: json["extra"] == null ? null : Extra.fromMap(json["extra"]),
    android: json["android"] == null ? null : Android.fromMap(json["android"]),
  );
}

class Android {
  Android({
    this.isCustomNotification = false, // add your custom default value
    this.ringtonePath,
    this.backgroundColor,
    this.backgroundUrl,
    this.actionColor,
  });

  bool isCustomNotification;
  String? ringtonePath;
  String? backgroundColor;
  String? backgroundUrl;
  String? actionColor;

  factory Android.fromMap(Map<String, dynamic> json) => Android(
    isCustomNotification: json["isCustomNotification"],
    ringtonePath: json["ringtonePath"],
    backgroundColor: json["backgroundColor"],
    backgroundUrl: json["backgroundUrl"],
    actionColor: json["actionColor"],
  );
}

class Extra {
  Extra({
    this.caller,
    this.callee,
    this.callerImage,
    this.calleeName,
    this.uuid,
    this.callType,
    this.callerName,
  });

  String? caller;
  String? callee;
  String? callerImage;
  String? calleeName;
  String? uuid;
  String? callType;
  String? callerName;

  factory Extra.fromMap(Map<String, dynamic> json) => Extra(
    caller: json["caller"],
    callee: json["callee"],
    callerImage: json["callerImage"],
    calleeName: json["calleeName"],
    uuid: json["uuid"],
    callType: json["callType"],
    callerName: json["callerName"],
  );
}

Now if you type

final event = eventFromMap(rawEvent.toString()); // Your response

You can use event.body?.extra?.caller for example to access data with autocomplete benefit which is better than maps in my opinion

CodePudding user response:

Thanks for your quick solution Sir but it still gives me the same errors. Luckily, I explored the package and found its class called CallEvent with its fields - String name and dynamic body so if the body field is Map, we will be able to get body value as Map from the class.

if (event!.body is Map) {
  final extraData = event.body["extra"];
  print(extraData);
}

I hope it may help someone else in the future. Thanks! Happy New Year to you all!!

  •  Tags:  
  • Related