Retrofit response returning null in Android

2020-06-16 03:40发布

问题:

I wanted to display a text from a JSON value. I'm using Retrofit to make API call I don't know if I'm doing it right. Anyway here's my code.

Here's the url link: http://api.icndb.com/jokes/random .

The website will display a random joke each time. Here's the example of an output from the website:

{ "type": "success", "value": { "id": 175, "joke": "When Chuck Norris was a baby, he didn't suck his mother's breast. His mother served him whiskey, straight out of the bottle.", "categories": [] } } 

fragment.java

    String url = "http://api.icndb.com/";

    Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(url)
            .addConverterFactory(GsonConverterFactory.create());

    Retrofit retrofit = builder.build();

    RetroFitHelper client = retrofit.create(RetroFitHelper.class);
    Call<Api> call = client.findJoke("random");

    call.enqueue(new Callback<Api>() {
        @Override
        public void onResponse(Response<Api> response, Retrofit retrofit) {

            String result = response.body().getJoke();

            Toast.makeText(getContext()," The word is: " + result ,Toast.LENGTH_LONG).show();
        }

        @Override
        public void onFailure(Throwable t) {
            Toast.makeText(getContext()," Error..." ,Toast.LENGTH_LONG).show();

        }
    });

RetroFitHelper.java

public interface RetroFitHelper {

    @GET("/jokes/{random}")
    Call<Api> findJoke(@Path("random") String random);

}

Model class

public class Api {

    @SerializedName("joke")
    private String joke;

    public String getJoke() {
        return joke;
    }

    public void setJoke(String joke){
        this.joke = joke;
    }
}

回答1:

The provided json response has a json object named value inside another json object(It is of the form {..,"value":{}}). So we need two model classes - one for the outer json object and another one for the inner json object(value).

You will need to have two model classes like this

public class Api {

@SerializedName("type")
@Expose
private String type;
@SerializedName("value")
@Expose
private Value value;

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public Value getValue() {
return value;
}

public void setValue(Value value) {
this.value = value;
}

and the following one for value object

public class Value {

@SerializedName("id")
@Expose
private Integer id;
@SerializedName("joke")
@Expose
private String joke;
@SerializedName("categories")
@Expose
private List<Object> categories = null;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getJoke() {
return joke;
}

public void setJoke(String joke) {
this.joke = joke;
}

public List<Object> getCategories() {
return categories;
}

public void setCategories(List<Object> categories) {
this.categories = categories;
}

}

Now, response.body() will have the result of outer json object(Api) and response.body().getValue() will have the result for inner json object(Value) .

Now in your response callback, get response like this

String result = response.body().getValue().getJoke();

Also make sure that you have the necessary internet permission declared in your manifest like this

<uses-permission android:name="android.permission.INTERNET" />

Do ensure you have the latest dependencies setup in your app level build.gradle file

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

implementation 'com.squareup.retrofit2:converter-gson:2.4.0'



回答2:

As @Aswin suggest and @Navneet answered you have problem in your POJO class. I suggest you to use jsonschema2pojo or RoboPOJOGenerator so next time you avoid to stuck this kind of error.

Steps

1) Go to http://www.jsonschema2pojo.org/

2) Paste your response over there and enter package and class name

3) Choose target language as Java or Kotlin(if you are using)

4) Source type as Json

5) Annotation style as Gson

6) Click Preview

7) Copy and paste those classes to your app package



回答3:

Their is a problem in your model class which you are using.

The response of api is :

{
"type": "success",
"value": {
    "id": 429,
    "joke": "Chuck Norris has never been accused of murder because his roundhouse kicks are recognized as &quot;acts of God.&quot;",
    "categories": []
}
}

So for getting value of joke from response as a string your model class should be like this :

public class Api implements Serializable {

@SerializedName("type")
@Expose
private String type;
@SerializedName("value")
@Expose
private Value value;

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public Value getValue() {
    return value;
}

public void setValue(Value value) {
    this.value = value;
}
}

and your Value Class is :

public class Value implements Serializable
{
@SerializedName("id")
@Expose
private Integer id;
@SerializedName("joke")
@Expose
private String joke;
@SerializedName("categories")
@Expose
private List<Object> categories = null;

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getJoke() {
    return joke;
}

public void setJoke(String joke) {
    this.joke = joke;
}

public List<Object> getCategories() {
    return categories;
}

public void setCategories(List<Object> categories) {
    this.categories = categories;
}
}

And now you can get your value like this :

 call1.enqueue(new Callback<Api>() {
        @Override
        public void onResponse(Call<Api> call, Response<Api> response) {

            if (response.isSuccessful()) {
                String jokeValue = response.body().getValue().getJoke();
            }
        }

        @Override
        public void onFailure(Call<Api> call, Throwable t) {

            t.printStackTrace();
        }
    });

Do changes as per you requirement.

Happy Coding..



回答4:

Add this permission in your AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />

Add this in your build.gradle (Module:app)

compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'com.google.code.gson:gson:2.8.2'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

Add this interface ,

public interface ApiInterface {
public static final String BASE_URL = "http://api.icndb.com";

@GET("/jokes/{random}")
Call<Api> GetApiResponse(@Path("random") String random);


public class ApiClient {
    public static ApiInterface apiInterface;

    public static ApiInterface getApiInterface() {
        if (apiInterface == null) {
            Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
            apiInterface = retrofit.create(ApiInterface.class);
            return apiInterface;
        } else {
            return apiInterface;
        }
    }

}


}

Create 2 Model Class : com.example.app.Api.java

package com.example.app;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Api {

@SerializedName("type")
@Expose
 private String type;
@SerializedName("value")
 @Expose
 private Value value;

 public String getType() {
 return type;
 }

public Value getValue() {
return value;
}

}

Create Value Model Class : com.example.app.Value.java

package com.example.app;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Value {

@SerializedName("id")
@Expose
private Integer id;
@SerializedName("joke")
@Expose
private String joke;

public int getId() {
return id;
}

public String getJoke() {
return joke;
}

}

Add this code in your Activity onCreate() Method

  ApiInterface.ApiClient.getApiInterface().GetApiResponse('random').enqueue(new Callback<Api>() {
                @Override
                public void onResponse(Call<Api> call, Response<Api> response) {
                  String Joke=response.body.getValue().getJoke();
                    Toast.makeText(MainActivity.this, Joke, Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onFailure(Call<Api> call, Throwable t) {

                }
            });