Почему я получаю нулевой объект?

#java #android #json #retrofit #retrofit2

#java #Android #json #модернизация #retrofit2

Вопрос:

Я пытаюсь получить данные JSON https://newsapi.org/v1/articles с помощью Retrofit, но я новичок в этом, и до сих пор это было довольно запутанно.

Из того, что я могу сказать, мне удалось установить успешное соединение. Однако по какой-то причине, которую я еще не смог определить, Retrofit не сопоставляет данные из строк JSON с моим NewsAPI классом.

Я опубликую код, который я использую в настоящее время, и я надеюсь, что кто-нибудь поможет мне разобраться в этом. Спасибо!

Activity.java :

 final TextView tvTest = (TextView) findViewById(R.id.tvTest);
String url = "https://newsapi.org";

NewsAPI_Interface client = NewsAPI_Adapter.createService(NewsAPI_Interface.class);
Call<List<NewsAPI>> call = client.getData("techcrunch", "APIkeygoeshere");

call.enqueue(new Callback<List<NewsAPI>>() {
            @Override
            public void onResponse(Call<List<NewsAPI>> call, Response<List<NewsAPI>> response) {
                if (response.body() != null) {
                    tvTest.setText(response.body().toString());

                    for (NewsAPI news: response.body()) {
                        System.out.println(news.source   " ("   news.status   ")");
                        tvTest.setText(news.source   " ("   news.status   ")");
                    }
                } else {
                    tvTest.setText("It's null, "   response.errorBody().toString()   ", "   call.request().url());
                }
            }

            @Override
            public void onFailure(Call<List<NewsAPI>> call, Throwable t) {
                tvTest.setText("An error ocurred!");
            }
        });
  

NewsAPI.java :

 public class NewsAPI {
    String status;
    String source;

public NewsAPI (String status, String source) {
        this.status = status;
        this.source = source;
    }
}
  

NewsAPI_Interface.java :

 public interface NewsAPI_Interface {
    @GET("/v1/articles")
    Call<List<NewsAPI>> getData(@Query("source") String source, @Query("api_Key") String api_key);
}
  

NewsAPI_Adapter.java :

 public class NewsAPI_Adapter {
    public static final String API_BASE_URL = "https://newsapi.org";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(API_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create());

    public static <S> S createService(Class<S> serviceClass) {
        Retrofit retrofit = builder.client(httpClient.build()).build();
        return retrofit.create(serviceClass);
    }
}
  

Комментарии:

1. Если я помню, вы можете использовать только response.body() один раз из onResponse метода

2. Используете ли вы proguard?

3. Кроме того, @Query("api_Key") должно быть apiKey , если я правильно читаю. newsapi.org

4. И обратный вызов определен неправильно. Вы не ожидаете список, вы ожидаете один NewsAPI объект.

Ответ №1:

Из того, что я могу сказать, мне удалось установить успешное соединение

Ну, вы игнорируете Throwable здесь, где будет выведена ошибка.

 @Override
public void onFailure(Call<List<NewsAPI>> call, Throwable t) {
    tvTest.setText("An error ocurred!");
}
  

Ожидаемый вами ответ выглядит следующим образом

 {
    "status": "ok",
    "source": "techcrunch",
    ...
  

{ Там начинается объект, а не a List , поэтому вы должны определить свой интерфейс по-другому. Затем в документации говорится, что ключ API добавляется к URL с apiKey помощью, поэтому измените это.

 public interface NewsAPI_Interface {
    @GET("/v1/articles")
    Call<NewsAPI> getData(@Query("source") String source, @Query("apiKey") String api_key);
}
  

(Вам нужно определить другой объект для Article класса. Но это проблема Gson, а не модернизация)

Наконец, я помню, что где-то читал, что response.body() его следует вызывать только один раз.

 Call<NewsAPI> call = client.getData("techcrunch", "APIkeygoeshere");

call.enqueue(new Callback<NewsAPI>() {
    @Override
    public void onResponse(Call<List<NewsAPI>> call, Response<List<NewsAPI>> response) {
        final NewsAPI responseBody = response.body();
        if (responseBody != null) {
            tvTest.setText(responseBody.toString());

            String news = news.source   " ("   news.status   ")";
            Log.i("responseBody", news);
            tvTest.setText(news);

        } else {
            tvTest.setText("It's null, "   response.errorBody().toString()   ", "   call.request().url());
        }
    }

    @Override
    public void onFailure(Call<List<NewsAPI>> call, Throwable t) {
        tvTest.setText("An error ocurred!");
        Log.e("news Error", t.getMessage());
    }
});
  

Удачи!

Комментарии:

1. Спасибо, теперь у меня все работает! Я также успешно реализовал отсутствующий Articles класс, который был необходим для сопоставления массива JSON, используя ArrayList<Articles> on в соответствующей переменной NewsAPI класса. Просто оставляю это здесь для дальнейшего использования.

2. Привет, Kalz, я следил за этим моментом, как вы получили ArrayList<Articles> из ответа, я использую тот же api