아래의 글은 BOOSTER 서포터즈로 활동했던 케니(kart***)님이
작성한 부스트코스 후기입니다.
여러분들의 성원에 더 노력하는 부스트코스가 되겠습니다.
감사합니다.
******************************************
1)링크:https://blog.naver.com/kartmon/221636804166
2)작성날짜: 19/09/02
<본문내용>
5. JSON 이해하기
자바스크립트의 객체 포맷의 데이터를 주고 받을 때 사용되며,
중괄호를 이용해서 객체를 표현하고,
대괄호를 이용해서 배열을 표현한다.
서버에서 응답을 받으면 자바스크립트로 바꿔서 사용할 수 있는 장점이 있다.
그렇기 때문에 많은 곳에서 json을 많이 사용하고 있다.
json문자열이 넘어오면 그것을 자바 객체로 만들어주는 라이브러리가 있는데,
대표적으로 gson이라는 것을 사용한다.
//{ // "boxOfficeResult" //// :{ // "boxofficeType":"일별 박스오피스", // "showRange":"20120101~20120101", // "dailyBoxOfficeList" //// :[{ // "rnum":"1", //// "rank":"1", //// "rankInten":"0", //// "rankOldAndNew":"OLD", //// "movieCd":"20112207", //// "movieNm":"미션임파서블:고스트프로토콜", //// "openDt":"2011-12-15", //// "salesAmt":"2776060500", //// "salesShare":"36.3", //// "salesInten":"-415699000", //// "salesChange":"-13", //// "salesAcc":"40541108500", //// "audiCnt":"353274", //// "audiInten":"-60106", //// "audiChange":"-14.5", //// "audiAcc":"5328435", //// "scrnCnt":"697", //// "showCnt":"3223" //// }
public class MovieList { MovieListResult boxOfficeResult; String boxofficeType; String showRange; }
publicclassMovieListResult{ String boxofficeType; String showRange; ArrayList<org.mv.volley.Movie> dailyBoxOfficeList =newArrayList<Movie>();}
public class Movie { String rnum; String rank; String rankInten; String rankOldAndNew; String movieCd; String movieNm; String openDt; String salesAmt; String salesShare; String salesInten; String salesChange; String salesAcc; String audiCnt; String audiInten; String audiChange; String audiAcc; String scrnCnt; String showCnt; }
1) JSON 이해하기
생각해보기
JSON 포맷에서는 객체의 속성이 가지는 값으로 다시 객체를 넣을 수 있는데 객체 안에 객체를 넣고 또 그 객체 안에 객체를 넣을 수 있는 걸까요?
- 사용할 수 있지만 코드를 읽거나 수정해야할 때에는 복잡하기 때문에 지양해야할 것 같습니다.
JSON 포맷에서는 배열 안에 들어있는 객체의 속성이 가지는 값으로 다시 배열을 넣을 수 있는 걸까요?
- 네 역시 가능할 것 같습니다만 위와 같은 이유가 발생 할 수 있을 것 같습니다.
2) Gson 사용하기
gson을 사용하기 위해 아래와 같이 gradle에 추가한다.
가져올 데이터
dependencies { implementation 'com.android.volley:volley:1.1.0' implementation 'com.google.code.gson:gson:2.8.2'}
응답을 받으면 processResponse메소드에서 gson을 이용하여 객체를 생성하여
데이터 가져와서 처리할 수 있다.
newResponse.Listener<String>(){ @Override publicvoidonResponse(String response){println("응답 -> "+ response);//응답받은 문자열 처리processResponse(response);}},
publicvoidprocessResponse(String response){ Gson gson =newGson();//무비리스트 객체 생성 MovieList movieList = gson.fromJson(response,MovieList.class);if(movieList !=null){ int countMovie = movieList.boxOfficeResult.dailyBoxOfficeList.size();println("박스오피스 타입 : "+movieList.boxOfficeResult.boxofficeType);println("응답받은 영화 갯수 : "+ countMovie);}}
publicclassMainActivityextendsAppCompatActivity{ TextView textView; @Override protectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); textView =(TextView)findViewById(R.id.textView); Button button =(Button)findViewById(R.id.button); button.setOnClickListener(newView.OnClickListener(){ @Override publicvoidonClick(View view){//request 메소드 호출sendRequest();}});//메인이 만들어질때 동시에 requestQueue객체 초기화if(AppHelper.requestQueue ==null){ AppHelper.requestQueue = Volley.newRequestQueue(getApplicationContext());}}//request객체에 요청을 보내는 메소드publicvoidsendRequest(){//String url = "http://www.google.com"; String url ="http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=430156241533f1d058c603178cc3ca0e&targetDt=20120101"; StringRequest request =newStringRequest(//get방식으로 요청한다. Request.Method.GET,//전달 할 url url,//정상 응답일 경우newResponse.Listener<String>(){ @Override publicvoidonResponse(String response){println("응답 -> "+ response);//응답받은 문자열 처리processResponse(response);}},//잘못된 응답일 경우newResponse.ErrorListener(){ @Override publicvoidonErrorResponse(VolleyError error){println("에러 -> "+ error.getMessage());}}){//request 안에서 재정의를 할 수 있다.//요청 파라미터를 수정하기 위한 메소드 @Override protected Map<String, String>getParams() throws AuthFailureError { Map<String,String> params =newHashMap<String, String>();return params;}};//매번 받은 결과를 그대로 보여준다. request.setShouldCache(false);//requestQueue에 request를 추가한다. AppHelper.requestQueue.add(request);println("요청 보냄.");}publicvoidprocessResponse(String response){ Gson gson =newGson();//무비리스트 객체 생성 MovieList movieList = gson.fromJson(response,MovieList.class);if(movieList !=null){ int countMovie = movieList.boxOfficeResult.dailyBoxOfficeList.size();println("박스오피스 타입 : "+movieList.boxOfficeResult.boxofficeType);println("응답받은 영화 갯수 : "+ countMovie);}}//텍스트 뷰를 추가하는 메소드publicvoidprintln(String data){ textView.append(data +"\n");}}
생각해보기
JSON 문자열을 직접 파싱하는 코드를 만드는 경우와 Gson을 사용하는 경우를 비교하면 코드 양이 얼마나 차이날까요?
- gson을 사용하면 객체를 만들어서 사용할 수 있기 떄문에 코드양이 상당히 많이 줄어들 것 같습니다.
JSON 문자열에서 배열 안에 배열이 들어가는 경우에는 자바 클래스를 정의할 때 많이 복잡해질까요?
- 배열안에 배열이 들어간다면, 이를 객체로 생성하여 사용한다면 별로 복잡해지지 않을 거라고 생각합니다.
1) 이미지 다운로드
데이터에서 이미지를 다운로드 받아야 앱에 보여줄수 있다.
AsyncTask를 이용하여 BITMAP을 처리할 수 있다.
이 외에도 universal imageLoader 와 같은 외부 라이브러리를 이용하여 다운받아 처리할 수 있다.
ImageLoadTask.java
public class ImageLoadTask extends AsyncTask<Void,Void, Bitmap> { private String urlStr; private ImageView imageView; //url과 비트맵을 매칭 해주는 작 private static HashMap<String,Bitmap> bitmapHash = new HashMap<String,Bitmap>(); //생성자 public ImageLoadTask(String urlStr, ImageView imageView){ this.urlStr = urlStr; this.imageView = imageView; } //1번째 실행 @Override protected void onPreExecute() { super.onPreExecute(); } //2번째 실행 @Override protected Bitmap doInBackground(Void... voids) { Bitmap bitmap = null; try{ //이미 비트맵 주소가 들어있다면 if(bitmapHash.containsKey(urlStr)){ Bitmap oldBitmap = bitmapHash.remove(urlStr); if(oldBitmap != null){ //비트맵을 메모리에서 제거해준다. oldBitmap.recycle(); oldBitmap=null; } } URL url = new URL(urlStr); //주소에 접근해서 이미지라면 비트맵으로 바꿔서 저장 bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream()); //새롭게 해쉬에 저장 bitmapHash.put(urlStr,bitmap); //외부 라이브러리를 사용한다면 파일로 저장했다가 같은 url로 요청하면 로컬파일로 요청하여 이용한다. }catch (Exception e){ e.printStackTrace(); } return bitmap; } //3번쨰 실행 @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); } //4번째 실행 //비트맵 처리 @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); //이미지뷰에 설정 imageView.setImageBitmap(bitmap); //혹시나 설정이 안될경우를 위해서 다시 설정 imageView.invalidate(); } }
ImageView imageView; @Override protectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); textView =(TextView)findViewById(R.id.textView); imageView =(ImageView)findViewById(R.id.imageView); Button button =(Button)findViewById(R.id.button); button.setOnClickListener(newView.OnClickListener(){ @Override publicvoidonClick(View view){//request 메소드 호출sendRequest();}}); Button button2 =(Button)findViewById(R.id.button2); button2.setOnClickListener(newView.OnClickListener(){ @Override publicvoidonClick(View view){sendImageRequest();}});//메인이 만들어질때 동시에 requestQueue객체 초기화if(AppHelper.requestQueue ==null){ AppHelper.requestQueue = Volley.newRequestQueue(getApplicationContext());}}publicvoidsendImageRequest(){ String url ="https://movie-phinf.pstatic.net/20190524_104/1558663170174Q2mmw_JPEG/movie_image.jpg"; ImageLoadTask task =newImageLoadTask(url,imageView);//이미지를 가져와서 비트맵으로 만들어 뿌려준다. task.execute();}
생각해보기
UniversalImageLoader와 같은 외부 라이브러리를 사용하면 소스 코드의 양이 얼마나 더 줄어들까요?
- 비트맵을 반복 처리하는 것과 같은 메모리 처리 작업 코드가 줄어들기 때문에 이러한 내용의 코드를 줄일 수 있을 것 같습니다.
UniversalImageLoader와 같은 외부 라이브러리를 사용할 때 코드의 양이 줄어든다는 것 외에 어떤 장점이 있을까요?
- 외부라이브러리를 사용하면 여기에 제공하는 메소드들을 추가로 사용할 수 있을 것 같습니다.
1) 영화 API
서버에 응답을 받고 데이터를 사용할 수 있도록 만들어 진것으로, 영화 api를 사용할 수 있다.
아래는 영화 api 주소의 사용 방법이다.
위와 같이 보여지게 되며 이를 이용하여 데이터를 처리할 수 있다.
생각해보기
영화 목록 요청에 대한 응답으로 받은 문자열에는 영화에 대한 정보가 몇 개나 들어있나요?
- 총 12개의 정보가 들어 있습니다.
영화 상세 요청으로 받은 응답의 속성들과 앱의 화면에 추가했던 각각의 뷰를 매칭해볼 수 있을까요?
- 네 상세 요청에 관련된 json객체를 만들고, 이를 gson으로 객체로 만들어 불러온 후 데이터를 처리하면 충분히 가능 하다고 생각합니다.
*********************************************