Модификация Android разобрать вложенный ответ JSON в списке - PullRequest
0 голосов
/ 22 сентября 2018

Я создаю приложение Android на основе News API, которое загружает новости определенного канала, например, ABC News, в MainFragment с помощью RecyclerView.

Я выполняю вызов API для этого в MainFragment следующим образом:

MainFragment.java

public class MainFragment extends Fragment
{
   protected RecyclerView recyclerView;
   protected NewsAdapter adapter;
   protected String API_KEY;
   String sourceTitle, sourceID;
   List<Articles> articleList;

public MainFragment() {

}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState)
{
    ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_main, null);

    sourceTitle = "ABC News";
    sourceID = "abc-news";

    getActivity().setTitle(sourceTitle);

    API_KEY = getString(R.string.API_KEY);

    recyclerView = root.findViewById(R.id.recyclerview);

    RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());

    ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);

    Call<News> call = apiService.getArticles(sourceID, API_KEY);

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

            if (response != null && response.isSuccessful())
            {
                articleList = response.body().getArticles();
                populateRecycleView();
            }
            else
            {
                Toast.makeText(getActivity(), "Something went wrong..", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(Call<News> call, Throwable t)
        {
            Toast.makeText(getActivity(), "Error in API Call", Toast.LENGTH_SHORT).show();
        }
    });

    recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity().getApplicationContext(), recyclerView, new ClickListener() {
        @Override
        public void onClick(View view, int position)
        {
            //onclick code
        }

        @Override
        public void onLongClick(View view, int position) {
        }
    }));
    return root;
}

     private void populateRecycleView()
     {
         if (articleList.isEmpty() || articleList.size() == 0)
         {
            recyclerView.setAdapter(null);
            Toast.makeText(getActivity(), "Error in List", Toast.LENGTH_SHORT).show();
         }
         else
         {
            adapter = new NewsAdapter(articleList, getActivity());
            recyclerView.setAdapter(adapter);
         }
    }

При выполнении articleList = response.body().getArticles() возникает ошибка, и массив остается пустым.

Вызов API не загружает значения внутри него.

Я создал два класса Retrofit: APIInterface и APIClient, который выполняет вызов GET API: https://newsapi.org/v2/top-headlines?sources=abc-news&apiKey=MY_API_KEY.

APIInterface.java

  public interface ApiInterface
 {
   @GET("top-headlines")
   Call<List<News>> getArticles(@Query("sources") String source, @Query("apiKey") String apiKey);
 }

APIClient.java

 public class ApiClient
 {
  public static final String BASE_URL = "https://newsapi.org/v2/";
  private static Retrofit retrofit = null;


  public static Retrofit getClient()
  {
    if (retrofit==null)
    {
        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }
    return retrofit;
  }
 }

Я не могу понять, правильно ли я выполняю вызов API в двух вышеупомянутых классах, потому что данные JSON не получаютсяпроанализирован в моем списке ArctilesList и в моем адаптере массива.

Приложение падает при выполнении вызова API.

Обратите внимание: вызовы API работают.Адаптер успешно загружен с результатами API.

1 Ответ

0 голосов
/ 24 сентября 2018

Первое, что вам нужно понять, это метод Retrofit Call#enqueue(), который является асинхронным.Ваш код выполняется сверху вниз.Метод среднего времени enqueue() инициирует асинхронный запрос к API и возвращает успешный ответ на метод onResponse(), если он успешен, иначе метод onFailure().

Итак, как решить проблему с кодом?

Прежде всего вам нужно создать классы POJO (если вы еще не создали) для ответа API, как показано ниже.

Article.java

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

public class Article {

    @SerializedName("source")
    @Expose
    private Source source;
    @SerializedName("author")
    @Expose
    private String author;
    @SerializedName("title")
    @Expose
    private String title;
    @SerializedName("description")
    @Expose
    private String description;
    @SerializedName("url")
    @Expose
    private String url;
    @SerializedName("urlToImage")
    @Expose
    private Object urlToImage;
    @SerializedName("publishedAt")
    @Expose
    private String publishedAt;
    @SerializedName("content")
    @Expose
    private String content;

    // constructors

    // getters and setter methods

    // use Alt + Insert to generate constructors, getter and setter methods in Android Studio

}

Source.java

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

public class Source {

    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("name")
    @Expose
    private String name;

    // constructors

    // getters and setter methods
}

News.java

import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class News {

    @SerializedName("status")
    @Expose
    private String status;
    @SerializedName("totalResults")
    @Expose
    private Integer totalResults;
    @SerializedName("articles")
    @Expose
    private List<Article> articles = null;

    // constructors

    // getters and setter methods
}

Теперь в вашем классе MainFragment внесите следующие изменения,

public class MainFragment extends Fragment {

    // other part of the code here

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {

        // other part of the code here

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

                if (response != null && response.isSuccessful()) {

                    articleList = response.body().getArticles();

                    // request is successful just populate data in RecyclerView

                    populateRecyclerView(); 

                } else {

                    Toast.makeText(getActivity(), "Something went wrong...", Toast.LENGTH_SHORT).show();

                }
            }

            @Override
            public void onFailure(Call<News> call, Throwable t) {
                Toast.makeText(getActivity(), "Error in API Call", Toast.LENGTH_SHORT).show();
            }
        });

        // just move ArrayList checking and setting adapter part code into some other method

        // other part of the code here

    }

    private void populateRecyclerView() {

        if (articleList.isEmpty() || articleList.size() == 0) {
            recyclerView.setAdapter(null);
            Toast.makeText(getActivity(), "Error in List", Toast.LENGTH_SHORT).show();
        } else {
            adapter = new NewsAdapter(articleList, getActivity());
            recyclerView.setAdapter(adapter);
        }

    }

}

Не игнорировать Throwable объект в методе onFailure().Просто регистрируйте сообщения об ошибках вместо того, чтобы показывать сообщения об ошибках в Toast.

Log.e("TAG", "Error occurred...", t);

Таким образом, вы можете легко узнать, что пошло не так при выполнении запроса API.

Я пропустил некоторую часть вашего кодав моем ответе, поскольку это правильно и делает мой ответ немного длинным.Пожалуйста, просмотрите название метода и комментарии, которые я правильно использовал в своем ответе.

...