0

I have class in Flutter:

class Foo {
  String id;
  int power;

  Foo (this.id, this.power);

  Map toJson() => {
    'id': id,
    'power': power
  };
}

I've created a instance of this object and pass it to Android via MethodChannel as a String:

_myChannel.invokeMethod('custom_event', {
      'foo': foo.toJson().toString(),
});

In Android I retrive that string and want to convert to Foo object on Android side so:

val fooString = call.method.argument<String>("foo")
//output: {id: my_id, power: 23}

val response = fooString?.let { Response(it) }
//output {"id":"my_id","power":"23"}

Helper class:

class Response(json: String) : JSONObject(json) {
        val data = this.optJSONArray(null)
            ?.let { 0.until(it.length()).map { i -> it.optJSONObject(i) } } // returns an array of JSONObject
            ?.map { FooJson(it.toString()) } // transforms each JSONObject of the array into Foo
    }

    class FooJson(json: String) : JSONObject(json) {
        val id: String = this.optString("id")
        val power: String = this.optInt("power")
    }

How I can convert response to my Kotlin's class?

Wafi_ck
  • 1,045
  • 17
  • 41
  • Could you specify a problem please? Because you have Response class that parse the JSON. But it looks weird because you trying parse the array instead of object – powerman23rus Oct 25 '22 at 12:08
  • Yeah, I want to pass list of objects from Flutter to Android as a String and then convert string to list of objects again. – Wafi_ck Oct 25 '22 at 18:08

1 Answers1

1

Since Foo just contains a string and an integer, both of which are supported by the default message codec, it would make sense to simply pass those two values in a map. (In fact, you already have a method that creates that map, toJson, though a better name might be toMap.)

Don't then call toString on that map; instead use:

_myChannel.invokeMethod('custom_event', foo.toMap());

You are now invoking the method and passing the map. At the native end, you are going to look for the members using their map keys (i.e. id and power) using .argument<T> as you've tried, as follows:

val id = call.method.argument<String>("id");

You could, of course, then create a POJO that wraps an object around those two values, if really necessary.

For more complex messages, consider Pigeon. If you really want to use JSON as your method of serialization, look at the existing JSON message codec.

Richard Heap
  • 48,344
  • 9
  • 130
  • 112
  • I want to handle passing list of Foo objects so I thought parsing object to string and then to json is good idea. I don't want to use any external library to handle it. – Wafi_ck Oct 25 '22 at 17:38
  • 1
    It's not a particularly good idea, since the default codec can already do lists, maps, strings, etc etc. Why re-invent the wheel? If you want to pass a list of Foos, turn each Foo to a map, put them in a list and pass the list to invoke method. At the Java end you'll get an ArrayList of HashMaps - easy to traverse. – Richard Heap Oct 25 '22 at 18:11
  • What should i use if my Foo class has id, power and 2 more variables? – Wafi_ck Oct 25 '22 at 18:20
  • 1
    The same map with two extra key/values, for example `{.... 'isAlive': isAlive, 'logPower': logPower}` - showing an example of being able to pass a boolean and double straight through. – Richard Heap Oct 25 '22 at 18:38