使用Retrofit在JSON数组上的空指针异常

时间:2016-12-04 21:22:43

标签: java android json retrofit

我得到这个错误java.lang.NullPointerException:尝试在空对象引用'上调用接口方法' java.lang.Object java.util.List.get(int)。当我尝试从列表中获取值或返回它的大小时,我无法找到错误。 首先,我正在使用food2fork中的API,因此我可以根据用户的输入(成分)获得一些食谱。 This is how the results are returned and how the JSON structure is. If you want to see the parameters go here http://food2fork.com/about/api

这是我的界面。

     public interface ApiService {
    @GET("/search")
    Call<List<Recipe>> getRecipes(@Query("api") String api_key, @Query ("q")      StringBuilder st);

}

对象&#39;课程食谱

public class Recipe {


    @SerializedName("publisher")
    private String publisher; //to onoma tou ekdoth
    @SerializedName("f2f_url")
    private String f2f_url; //to url tis suntaghs sto site food2fork
    @SerializedName("title")
    private String title; //titlos tis suntaghs
    @SerializedName("source_url")
    private String source_url; //to url ths suntaghs se html
    @SerializedName("recipe_id")
    private int recipe_id; //to id ths suntaghs
    @SerializedName("image_url")
    private String image_url; //to url ths eikonas se jpg
    @SerializedName("social_rank")
    private double social_rank;
    @SerializedName("publisher_url")
    private String publisher_url; //to vasiko url tou ekdoth

    public String getPublisher() {
            return publisher;
    }

    public String getF2f_url() {
            return f2f_url;
    }

    public String getSource_url() {
            return source_url;
    }

    public String getTitle() {
            return title;
    }

    public int getRecipe_id() {
            return recipe_id;
    }

    public double getSocial_rank() {
            return social_rank;
    }

    public String getImage_url() {
            return image_url;
    }

    public String getPublisher_url() {
            return publisher_url;
    }

public void setPublisher(String publisher) {
    this.publisher = publisher;
}

public void setF2f_url(String f2f_url) {
    this.f2f_url = f2f_url;
}

public void setTitle(String title) {
    this.title = title;
}

public void setSource_url(String source_url) {
    this.source_url = source_url;
}

public void setRecipe_id(int recipe_id) {
    this.recipe_id = recipe_id;
}

public void setImage_url(String image_url) {
    this.image_url = image_url;
}

public void setSocial_rank(double social_rank) {
    this.social_rank = social_rank;
}

public void setPublisher_url(String publisher_url) {
    this.publisher_url = publisher_url;
}

    public Recipe(String publisher, String f2f_url, String title, String source_url, int recipe_id, String image_url, double social_rank, String publisher_url) {
            this.publisher = publisher;
            this.f2f_url = f2f_url;
            this.title = title;
            this.source_url = source_url;
            this.recipe_id = recipe_id;
            this.image_url = image_url;
            this.social_rank = social_rank;
            this.publisher_url = publisher_url;
    }

}

我的主要课程

public class ResponseMain extends AppCompatActivity {

RecyclerView recyclerView;
public static String getApiKey() {
    return API_KEY;
}

//to key API ths selidas pou mas epistrefei to json antikeimeno
private final static String API_KEY = "fe7a73e01ac9abc09db51ebf67019f94";
StringBuilder words;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("TAG", "MPIKA");
    setContentView(R.layout.activity_response);


    if (API_KEY.isEmpty()) {
        Toast.makeText(getApplicationContext(), "Please obtain your API key from food2fork.com first!", Toast.LENGTH_LONG);
        return;
    }
     recyclerView = (RecyclerView) findViewById(R.id.recipes_recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));


    words = addingItems_activity.getWords();
    getRetrofitArray();
}
public void getRetrofitArray() {

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    ApiService apiService = retrofit.create(ApiService.class);
    Call<List<Recipe>> call = apiService.getRecipes(API_KEY, words);

    call.enqueue(new Callback<List<Recipe>>() {
        @Override
        public void onResponse(Call<List<Recipe>> call, Response <List<Recipe>> response) {
            try {
                Log.d("Here comes the null exception","get title" + response.body().get(0).getTitle());
                List<Recipe> recipes = response.body();
                recyclerView.setAdapter(new Recipe_Adapter(recipes, R.layout.list_item_recipe, getApplicationContext()));
           }
            } catch (Exception e) {
                Log.d("onResponse", "There is an error", e);
                e.printStackTrace();


            }
        }

        @Override
        public void onFailure(Call <List<Recipe>> call,Throwable t) {
            Log.d("onFailure", t.toString());
        }
    });

}

} 如果

,还会从其他活动中添加这些词语
(itemList.size() == 1) {

                    words.append(itemList.get(0));
                }else{
                    for (int i = 0; i < (itemList.size() - 1); i++) {
                        words.append(itemList.get(i) + "%2C");

//%2C表明它们是分开的成分,我发现它是用来翻译逗号的符号                         }

                    words.append((itemList.get(itemList.size() - 1)));

                }

2 个答案:

答案 0 :(得分:1)

当您为Call<List<Recipe>>接口中的方法getRecipes()定义返回类型为ApiService时,Retrofit需要来自JSONArray类型的服务器的响应,它应该看起来像 -

[
  {
    "publisher": "Allrecipes.com",
    ...
  },
    ...
]

但响应来自服务器正在跟随 -

{
  "count": 1,
  "recipes": [
    {
      "publisher": "Allrecipes.com"
      ...
    },
      ...
  ]
}

因此,您需要解开编写自定义反序列化程序的响应,或者需要将列表包装到包装类中。

您的包装类可以像 -

public class Recipes{
        private List<Recipe> recipes;
        private int count;
        public List<Recipe> getRecipes() {
            return recipes;
        }

        public void setRecipes(List<Recipe> recipes) {
            this.recipes = recipes;
        }
    }

因此您的ApiService接口方法应返回Call<Recipes>

答案 1 :(得分:0)

所以我通过更改第一个查询标记来解决它,当然还有评论者所说的那个类。我有@QUERY api而不是key。这就是我改变界面的方式:

public interface ApiService {
    @GET("api/search/")
    Call<RootObject> getMyJSON(@Query("key") String api_key, @Query("q") StringBuilder st);

}

另外,我更改了Rest Class的基本URL,因为我将关键字放在界面

public class RestClient {

//gia na ginei h epikoinwnia me to API prepei na xrhsimopoihsw ton retrofit builder kai na prosdiorisw
//to url tou service
public static final String BASE_URL = "http://food2fork.com/";
private ApiService apiService;
        //"?key=";
        //+  addingItems_activity.getApiKey() + "&q=" + addingItems_activity.getWords();
private static Retrofit retrofit = null;

private static Retrofit getRetrofitInstance() {

    return new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();


  }

public static ApiService getApiService()
{
    return getRetrofitInstance().create(ApiService.class);
}
}

第一个答案说明了解决方案的其余部分。非常感谢!