denis_lor
denis_lor

Reputation: 6547

Retrofit decapsulate JSON webservices performance

I'm using Retrofit and I've created my ItemTypeAdapterFactory class that implements TypeAdapterFactory and create the read method... and everything works great, in my "response"/"data" (json) there is an array of object.

But I can see that it is very slow! I have an array of 1000/1500 object, and all the bootelneck is in my ItemTypeAdapterFactory because it goes into the "read" method as much as there are object, and looking at the log, it spends 10-15 seconds into the reading, and after it my `recyclerview get filled with data.

I'm sure the bottelneck is in the read method being called as many times as my array size, because consuming the same API with POSTMAN, it give me the response in half second.

Is there any faster way of implementing it? I receive response from using google like this:

{
  "message": {
     "response": : {
         "myArray": [
            "object 1" : {...},
             ....,
            "object 1500" : {...}
         ]
      },
     "status": "101",
     "statusmessage":"Record is inserted!"
  },
  "kind":"....",
  "etag":" .... "
}

So I use the ItemTypeAdapterFactory class in order to process the response which comes exactly in this form as JSON, and I get with retrofit everything inside "message" which is the only thing I'm interested in.

This is the code for calling ItemTypAdapterFactory before building the restAdapter in retrofit:

Gson gson = new GsonBuilder()
                .registerTypeAdapterFactory(new ItemTypeAdapterFactory()) 
                .setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
                .create();

And my ItemTypeAdapterFactory is this:

public class ItemTypeAdapterFactory implements TypeAdapterFactory {

    public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {

        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter<T>() {

            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            public T read(JsonReader in) throws IOException {

                JsonElement jsonElement = elementAdapter.read(in);
                if (jsonElement.isJsonObject()) {
                    JsonObject jsonObject = jsonElement.getAsJsonObject();
                    if (jsonObject.has("message") && jsonObject.get("message").isJsonObject()) {
                        jsonElement = jsonObject.get("message");
                    }
                }

                return delegate.fromJsonTree(jsonElement);
            }
        }.nullSafe();
    }
}

How can I make my retrofit call faster with this AdapterFactory settings? Thanks!

Upvotes: 0

Views: 400

Answers (2)

user4479689
user4479689

Reputation:

Take a look at this:

Factories should expect create() to be called on them for many types and should return null for most of those types.

Upvotes: 1

iagreen
iagreen

Reputation: 32016

It is worse than that, you are calling read for every element because you are returning a your TypeAdapter for all types. In your create method you should only return a new adapter for the type you are interested in, and null for others. From the TypeAdapterFactory docs --

Factories should expect create() to be called on them for many types and should return null for most of those types.

It will look something like --

public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
    if(type.getType != Item.class) {
        // Do not use custom adapter for other types
        return null;
    }
    final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
    final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);

    return new TypeAdapter<T>() {
        // your adapter code
    }

Upvotes: 1

Related Questions