[Android] JSON 데이터를 RecyclerView로 다루기
모든 내용은 Do it! 안드로이드 앱 프로그래밍을 바탕으로 정리한 것입니다.
JSON
JavaScript Object Notation
자바스크립트 객체 포맷 데이터를 주고받을 때 사용할 수 있도록 문자열로 표현한 것
→ 자바스크립트 객체 포맷과 거의 동일하며 속성의 이름과 문자열에 큰 따옴표를 사용하는 것에 차이가 있음
- 중괄호를 이용하여 객체를 만들 수 있음
- 각각의 속성은 콤마(,)로 구분되며, 각각의 속성 자체는 속성 이름(key)과 속성 값(value)이 콜론(:) 기호로 구분되어 한 쌍을 이룸
- 콜론 뒤에 값은 문자열이나 숫자와 같은 기본 자료형 뿐만 아니라 중괄호로 쌓인 객체가 올 수 있음
- 문자열 값에는 큰 따옴표를 붙이고 숫자에는 붙이지 않음
- 배열을 사용할 경우, 대괄호를 사용하며 그 안에 쉼표로 구분된 배열 원소들이 들어감
- 장점
- 가독성
- 가벼움 : XML은 데이터 마다 태그를 이용해 설명을 부여했지만, JSON은 key:value 형태
- 플랫폼 독립적 : JSON 형식만 지킨다면 어떤 시스템간이든 데이터 교환이 가능함
GSON
JSON 구조의 데이터를 Java 객체로 직렬화/역직렬화 해주는 Java 라이브러리 (JSON Object ↔ Java Object)
외부 라이브러리이므로 지난번 Volley와 같이 build.gradle에 GSON 라이브러리를 추가해야 함
[ 예제 ]
build.gradle(Module:app)
dependencies {
...
implementation 'com.android.volley:volley:1.1.0'
implementation 'com.google.code.gson:gson:2.8.7'
}
MovieList.class, MovieListResult.class, Movie.class
사용한 API : 영화진흥위원회 API
- API의 JSON 응답 포맷에 맞춰 새로운 자바 클래스를 정의함
- 변수의 이름은 JSON 문자열에서 속성의 key 값과 같아야 함
- JSON 속성의 value가 배열인 경우, ArrayList 자료형을 사용할 수 있음
- 배열 안에 들어가는 객체는 또 다른 클래스로 정의할 수 있음
public class MovieList {
MovieListResult boxOfficeResult;
}
public class MovieListResult {
String boxOfficeType;
String showRange;
ArrayList<Movie> dailyBoxOfficeList = new ArrayList<Movie>();
}
public class Movie {
String rnum, rank, rankInten, rankOldAndNew;
String movieCd, movieNm, openDt;
String salesAmt, salesInten, salesChange, salesAcc;
String audiCnt, audiInten, audiChange, audiAcc;
String scrnCnt, showCnt;
}
VolleyActivity.java
Gson 객체의 fromJson() 메서드로 문자열을 자바 객체로 변환
...
public void makeRequest() {
...
println("응답-> " + response);
processResponse(response);
}
// GSON 라이브러리 사용
public void processResponse(String response) {
Gson gson = new Gson();
MovieList movieList = gson.fromJson(response, MovieList.class);
println("영화 정보의 수 : "+movieList.boxOfficeResult.dailyBoxOfficeList.size());
}
},
RecyclerView를 이용하여 나타내기
RecyclerView
ListView의 개선판!
'Recycler'라는 단어의 의미(재활용하는 사람)처럼 사용했던 것을 다시 사용한다는 의미
즉, 아이템을 표시하기 위해 생성한 뷰를 재활용(recycler)해야 함.
이를 위해 기본적으로 뷰홀더(ViewHolder) 패턴을 사용해야 함!자세한 내용은 다음 포스팅에~
[ 하고자 하는 것 ]
조회할 날짜를 YYYYMMDD 형식으로 입력하고 조회 버튼을 누르면 해당 날짜의 박스오피스 데이터를 불러와 리스트로 제공해보자!
MovieAdapter.java
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.ViewHolder> {
class ViewHolder extends RecyclerView.ViewHolder {
TextView title, date, count;
public ViewHolder(@NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.movie_title);
date = itemView.findViewById(R.id.movie_openDt);
count = itemView.findViewById(R.id.movie_audiCnt);
}
public void setItem(Movie item) {
title.setText(item.movieNm);
date.setText(item.openDt);
count.setText(item.audiCnt + " 명");
}
}
ArrayList<Movie> movies = new ArrayList<Movie>();
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.movie_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// 실제로 movie_item 레이아웃을 변경하는 메소드
Movie movie = movies.get(position);
holder.setItem(movie);
}
@Override
public int getItemCount() {
// 데이터의 개수
return (movies != null? movies.size() : 0);
}
// 데이터 세팅을 위한 메소드
public void setItems(ArrayList<Movie> items) {
this.movies = items;
}
}
- 미리 만들어 둔 화면에 필요한 영화 제목, 개봉일, 관람객 수에 대한 TextView를 ViewHolder에서 연결함
- 뷰홀더(ViewHolder)가 만들어지는 시점은 onCreateViewHolder() 안에서 movie_item.xml을 인플레이션하고 반환
- 어댑터 안에 Movie 객체들을 넣는 시점은 웹 응답을 받았을 때가 되어야 하므로 RecyclerView 객체에 어댑터만 설정
GsonActivity.java
- RecyclerView를 세로 방향으로 볼 수 있도록 레이아웃 매니저(LayoutManager) 설정
- 버튼을 누르면 요청 객체를 만들고 요청 큐에 넣어줌
- 해당 날짜를 EditText에서 가져와서 url 문자열을 만들도록 함
- StringRequest 클래스를 이용하여 요청 객체를 만듦
- processResponse() 메서드에서 GSON을 이용하여 JSON 문자열을 MovieList 객체로 반환
- 어댑터에 데이터를 추가했다면 notifyDataSetChanged()를 사용해야 변경된 내용이 RecyclerView에 반영됨
public class GsonActivity extends AppCompatActivity {
EditText dateEditText;
RecyclerView recyclerView;
MovieAdapter adapter;
static RequestQueue requestQueue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gson);
dateEditText = findViewById(R.id.gson_date_edittext);
recyclerView = findViewById(R.id.recyclerview);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
adapter = new MovieAdapter();
recyclerView.setAdapter(adapter);
Button button = findViewById(R.id.gson_button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
makeRequest();
}
});
if (requestQueue == null) {
requestQueue = Volley.newRequestQueue(getApplicationContext());
}
}
public void makeRequest() {
String url = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=f5eef3421c602c6cb7ea224104795888&targetDt="+
dateEditText.getText().toString();
StringRequest request = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("GSON", "응답-> " + response);
processResponse(response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("GSON","에러-> "+error.getMessage());
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
return params;
}
};
request.setShouldCache(false);
requestQueue.add(request);
Log.d("GSON","요청 보냄");
}
// GSON 라이브러리 사용
public void processResponse(String response) {
Gson gson = new Gson();
MovieList movieList = gson.fromJson(response, MovieList.class);
Log.d("GSON","영화 정보의 수 : "+movieList.boxOfficeResult.dailyBoxOfficeList.size());
adapter.setItems(movieList.boxOfficeResult.dailyBoxOfficeList);
adapter.notifyDataSetChanged();
}
}
*Volley 라이브러리와 인플레이션에 대한 자세한 내용은 아래 포스팅 참고!