관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[안드로이드] Retrofit2 정리 예제 본문

안드로이드/자바 & Previous

[안드로이드] Retrofit2 정리 예제

막무가내막내 2019. 6. 14. 21:36
728x90

 

이번에는 레트로핏(Retrofit2)에 대해 정리해보는 포스팅을 가져보도록 하겠습니다.

http://www.kobis.or.kr/kobisopenapi/homepg/main/main.do

 

영화진흥위원회 오픈API

 

www.kobis.or.kr

레트로핏 실습을 위해 영화진흥위원회 오픈 API를 참고하여 통신하도록 하겠습니다. 그 중에서도 주간/주말 박스오피스 순위기준으로(http://www.kobis.or.kr/kobisopenapi/homepg/apiservice/searchServiceInfo.do) 영화의 제목과 순위 일일관객수 누적관객수를 리사이클러뷰 형태로 불러와보도록 하겠습니다.

먼저 시작하기전에 해당사이트에서 회원가입을하고 api접근 허용키를 받아야 데이터를 불러올 수 있습니다.

 

1. 먼저 매니페스트에 인터넷접근권한을 추가해줍니다. 그리고 android:usesCleartextTraffic="true"도 application태그 안에 추가해주도록 합니다.

  <uses-permission android:name="android.permission.INTERNET"/>

 

2. build.gradle에 추가해줍니다.

    /*레트로핏2, GSON, 리사이클러뷰*/
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'

 

 

 

3. 사이트에서 JSON 사이트에 접속합니다. 

 

http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchWeeklyBoxOfficeList.json?key=430156241533f1d058c603178cc3ca0e&targetDt=20120101

 

 

 

 

4. 그럼 JSON형식으로 된 데이터들을 볼 수있을텐데 정렬되게 보기싶다면 https://youngest-programming.tistory.com/18

 

[안드로이드] json 포맷 정렬해주는 크롬 확장자 프로그램

https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa/related?hl=ko 위 사이트에 들어가서 밑과 같은 크롬 확장프로그램을 다운받으면 크롬 브라우저로 json포맷을 볼때..

youngest-programming.tistory.com

를 다운받아서 보시면 됩니다.!

 

5. 해당 JSON을 https://youngest-programming.tistory.com/72

 

[안드로이드] 레트로핏2(Retrofit2) Json코드 java코드로 변환해주는 사이트

http://www.jsonschema2pojo.org/ 불러오는 중입니다... 몽고디비같은 경우는 맨 밑의 Property word delimiters를 공백으로 해줘야 에러가 안난다고한다.

youngest-programming.tistory.com

를 참고해서 레트로핏통신을 해서 JSON -> GSON 변환이 가능하게 해줍니다. 이 사이트는 일일히 GSON으로 변환되게할 객체를 안만들어도되고 자동으로 JSON을 분석해서 자바클래스로 바꿔주는 역할을 합니다.

 

 

6. 이제 자바클래스를 만들었으면 먼저 xml 뷰를 어떻게 할지 보도록 하겠습니다. 매인액티비티xml과 리사이클러뷰 어댑터를 위한 아이템뷰 이렇게 2개를 만듭니다.

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
    android:id="@+id/boxoffice_recycler"
    android:layout_width="match_parent"
    android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>

</LinearLayout>

boxoffice_item

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    android:gravity="center_vertical"
    android:padding="8dp"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/rank"
        android:layout_width="25dp"
        android:background="#544B4B"
        android:text="1"
        android:textColor="#FFFFFF"
        android:gravity="center"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/movie_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:text="어벤저스"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height= "match_parent"
        android:orientation="vertical">
        <TextView
            android:id="@+id/count1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/count2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

 

 

7. 이제 5번에서 변환한 것을 이용해 클래스를 생성해주도록합니다. 복사 붙여넣기 하시면됩니다. 

JSON이 2중구조로 되있으니 데이터를 받는 클래스는 총 3개가 필요합니다.(변환사이트에 preview를 누르면 클래스가 3개가 나올겁니다. 그걸만드시면 됩니다. ) 

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


/*
"boxOfficeResult": {
"boxofficeType": "주말 박스오피스",
"showRange": "20111230~20120101",
"yearWeekTime": "201152",
"weeklyBoxOfficeList": [
{
"rnum": "1",
"rank": "1",
"rankInten": "0",
"rankOldAndNew": "OLD",
"movieCd": "20112207",
"movieNm": "미션임파서블:고스트프로토콜",
"openDt": "2011-12-15",
"salesAmt": "7840509500",
"salesShare": "35.8",
"salesInten": "-1706758500",
"salesChange": "-17.9",
"salesAcc": "40541108500",
"audiCnt": "1007683",
"audiInten": "-234848",
"audiChange": "-18.9",
"audiAcc": "5328435",
"scrnCnt": "697",
"showCnt": "9677"
},
*/

import java.util.List;


public class BoxOfficeResult {

    @SerializedName("boxofficeType")
    @Expose
    private String boxofficeType;
    @SerializedName("showRange")
    @Expose
    private String showRange;
    @SerializedName("yearWeekTime")
    @Expose
    private String yearWeekTime;
    @SerializedName("weeklyBoxOfficeList")
    @Expose
    private List<WeeklyBoxOfficeList> weeklyBoxOfficeList = null;

    public String getBoxofficeType() {
        return boxofficeType;
    }

    public void setBoxofficeType(String boxofficeType) {
        this.boxofficeType = boxofficeType;
    }

    public String getShowRange() {
        return showRange;
    }

    public void setShowRange(String showRange) {
        this.showRange = showRange;
    }

    public String getYearWeekTime() {
        return yearWeekTime;
    }

    public void setYearWeekTime(String yearWeekTime) {
        this.yearWeekTime = yearWeekTime;
    }

    public List<WeeklyBoxOfficeList> getWeeklyBoxOfficeList() {
        return weeklyBoxOfficeList;
    }

    public void setWeeklyBoxOfficeList(List<WeeklyBoxOfficeList> weeklyBoxOfficeList) {
        this.weeklyBoxOfficeList = weeklyBoxOfficeList;
    }

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

/*
* weeklyBoxOfficeList": [
{
"rnum": "1",
"rank": "1",
"rankInten": "0",
"rankOldAndNew": "OLD",
"movieCd": "20112207",
"movieNm": "미션임파서블:고스트프로토콜",
"openDt": "2011-12-15",
"salesAmt": "7840509500",
"salesShare": "35.8",
"salesInten": "-1706758500",
"salesChange": "-17.9",
"salesAcc": "40541108500",
"audiCnt": "1007683",
"audiInten": "-234848",
"audiChange": "-18.9",
"audiAcc": "5328435",
"scrnCnt": "697",
"showCnt": "9677"
},
{
"rnum": "2",
"rank": "2",
"rankInten": "1",
"rankOldAndNew": "OLD",
"movieCd": "20112621",
"movieNm": "셜록홈즈 : 그림자 게임",
"openDt": "2011-12-21",
"salesAmt": "3436042500",
"salesShare": "15.7",
"salesInten": "-576328500",
"salesChange": "-14.4",
"salesAcc": "10678327500",
"audiCnt": "453533",
"audiInten": "-83422",
"audiChange": "-15.5",
"audiAcc": "1442861",
"scrnCnt": "363",
"showCnt": "5589"
},
* */
public class WeeklyBoxOfficeList {

    @SerializedName("rnum")
    @Expose
    private String rnum;
    @SerializedName("rank")
    @Expose
    private String rank;
    @SerializedName("rankInten")
    @Expose
    private String rankInten;
    @SerializedName("rankOldAndNew")
    @Expose
    private String rankOldAndNew;
    @SerializedName("movieCd")
    @Expose
    private String movieCd;
    @SerializedName("movieNm")
    @Expose
    private String movieNm;
    @SerializedName("openDt")
    @Expose
    private String openDt;
    @SerializedName("salesAmt")
    @Expose
    private String salesAmt;
    @SerializedName("salesShare")
    @Expose
    private String salesShare;
    @SerializedName("salesInten")
    @Expose
    private String salesInten;
    @SerializedName("salesChange")
    @Expose
    private String salesChange;
    @SerializedName("salesAcc")
    @Expose
    private String salesAcc;
    @SerializedName("audiCnt")
    @Expose
    private String audiCnt;
    @SerializedName("audiInten")
    @Expose
    private String audiInten;
    @SerializedName("audiChange")
    @Expose
    private String audiChange;
    @SerializedName("audiAcc")
    @Expose
    private String audiAcc;
    @SerializedName("scrnCnt")
    @Expose
    private String scrnCnt;
    @SerializedName("showCnt")
    @Expose
    private String showCnt;

    public String getRnum() {
        return rnum;
    }

    public void setRnum(String rnum) {
        this.rnum = rnum;
    }

    public String getRank() {
        return rank;
    }

    public void setRank(String rank) {
        this.rank = rank;
    }

    public String getRankInten() {
        return rankInten;
    }

    public void setRankInten(String rankInten) {
        this.rankInten = rankInten;
    }

    public String getRankOldAndNew() {
        return rankOldAndNew;
    }

    public void setRankOldAndNew(String rankOldAndNew) {
        this.rankOldAndNew = rankOldAndNew;
    }

    public String getMovieCd() {
        return movieCd;
    }

    public void setMovieCd(String movieCd) {
        this.movieCd = movieCd;
    }

    public String getMovieNm() {
        return movieNm;
    }

    public void setMovieNm(String movieNm) {
        this.movieNm = movieNm;
    }

    public String getOpenDt() {
        return openDt;
    }

    public void setOpenDt(String openDt) {
        this.openDt = openDt;
    }

    public String getSalesAmt() {
        return salesAmt;
    }

    public void setSalesAmt(String salesAmt) {
        this.salesAmt = salesAmt;
    }

    public String getSalesShare() {
        return salesShare;
    }

    public void setSalesShare(String salesShare) {
        this.salesShare = salesShare;
    }

    public String getSalesInten() {
        return salesInten;
    }

    public void setSalesInten(String salesInten) {
        this.salesInten = salesInten;
    }

    public String getSalesChange() {
        return salesChange;
    }

    public void setSalesChange(String salesChange) {
        this.salesChange = salesChange;
    }

    public String getSalesAcc() {
        return salesAcc;
    }

    public void setSalesAcc(String salesAcc) {
        this.salesAcc = salesAcc;
    }

    public String getAudiCnt() {
        return audiCnt;
    }

    public void setAudiCnt(String audiCnt) {
        this.audiCnt = audiCnt;
    }

    public String getAudiInten() {
        return audiInten;
    }

    public void setAudiInten(String audiInten) {
        this.audiInten = audiInten;
    }

    public String getAudiChange() {
        return audiChange;
    }

    public void setAudiChange(String audiChange) {
        this.audiChange = audiChange;
    }

    public String getAudiAcc() {
        return audiAcc;
    }

    public void setAudiAcc(String audiAcc) {
        this.audiAcc = audiAcc;
    }

    public String getScrnCnt() {
        return scrnCnt;
    }

    public void setScrnCnt(String scrnCnt) {
        this.scrnCnt = scrnCnt;
    }

    public String getShowCnt() {
        return showCnt;
    }

    public void setShowCnt(String showCnt) {
        this.showCnt = showCnt;
    }

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

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

public class Result {

    @SerializedName("boxOfficeResult")
    @Expose
    private BoxOfficeResult boxOfficeResult;

    public BoxOfficeResult getBoxOfficeResult() {
        return boxOfficeResult;
    }

    public void setBoxOfficeResult(BoxOfficeResult boxOfficeResult) {
        this.boxOfficeResult = boxOfficeResult;
    }

}

 

 

 

 

 

8. 그리고 통신을 위한 인터페이스를 생성해주도록 합니다. 사이트에서 다음과같이 보면은 필수적으로 요청파라미터를 2개보내고(API키와 날짜) 어디로 요청을 해야하는지 url이 나와있습니다. 이것을 참고하시면 됩니다. 참고로 baseUrl은 쓰지 않도록합니다. (앞대가리 대표) 만약 요청파라미터가 필요없으면 그냥 () 비어써도 되지만 여기서는 필요합니다.

 

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface BoxOfficeService {
    // http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.xml
    @GET("/kobisopenapi/webservice/rest/boxoffice/searchWeeklyBoxOfficeList.json?")
    Call<Result> getBoxOffice(@Query("key") String key,
                              @Query("targetDt") String targetDt);
}

 

 

 

 

9. 리사이클러뷰로 보여줘야하므로 어댑터를 미리 만들어보도록 하겠습니다. 영화제목과 순위 관객수를 뿌려줄겁니다.

(레트로핏 포스팅이므로 자세한 설명은 생략하도록 하겠습니다.)

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class BoxOfficeAdapter extends RecyclerView.Adapter<BoxOfficeAdapter.BoxOfficeViewHolder>{
    List<WeeklyBoxOfficeList> weeklyBoxOfficeLists = new ArrayList<>();
    Context context;

    public BoxOfficeAdapter(List<WeeklyBoxOfficeList> weeklyBoxOfficeLists, Context context) {
        this.weeklyBoxOfficeLists = weeklyBoxOfficeLists;
        this.context = context;
    }

    @NonNull
    @Override
    public BoxOfficeViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View rootView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.boxoffice_item, viewGroup, false);
        BoxOfficeViewHolder boxOfficeViewHolder = new BoxOfficeViewHolder(rootView);
        return boxOfficeViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull BoxOfficeViewHolder boxOfficeViewHolder, int i) {
        WeeklyBoxOfficeList weeklyBoxOfficeList = weeklyBoxOfficeLists.get(i);
        boxOfficeViewHolder.rankTextView.setText(weeklyBoxOfficeList.getRank()+"");
        boxOfficeViewHolder.movieNameTextView.setText(weeklyBoxOfficeList.getMovieNm());
        boxOfficeViewHolder.count1TextView.setText(weeklyBoxOfficeList.getAudiCnt()); //일일 관객수
        boxOfficeViewHolder.count2TextView.setText(weeklyBoxOfficeList.getAudiAcc()); //누적관객수

    }

    @Override
    public int getItemCount() {
        return weeklyBoxOfficeLists.size();
    }

    public class BoxOfficeViewHolder extends RecyclerView.ViewHolder {
        TextView rankTextView;
        TextView movieNameTextView;
        TextView count1TextView;
        TextView count2TextView;


        public BoxOfficeViewHolder(@NonNull View itemView) {
            super(itemView);
            rankTextView = itemView.findViewById(R.id.rank);
            movieNameTextView = itemView.findViewById(R.id.movie_name);
            count1TextView = itemView.findViewById(R.id.count1);
            count2TextView = itemView.findViewById(R.id.count2);
        }
    }

}

 

 

 

 

 

10. 마지막으로 메인액티비티에서 통신을 하고 데이터를 받아와서 리사이클러뷰에 뿌려줍니다. basUrl은 대표 url을 의미합니다. JSON이 2중 구조로 되있으므로 처음 데이터들을 받아오고 그 안의 WeeklyBoxOfficeList를 불러와서 해당 리스트의 데이터(클래스)를 어댑터에 add 해주도록합니다.

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
//http://www.kobis.or.kr/kobisopenapi/homepg/main/main.do
public class MainActivity extends AppCompatActivity {
    final String BASE_URL = "http://www.kobis.or.kr";
    Retrofit retrofit;
    BoxOfficeService boxOfficeService;
    RecyclerView boxoffice_recycler;

    String API_KEY = "당신의키를입력하세요";

    List<WeeklyBoxOfficeList> weeklyBoxOfficeLists = new ArrayList<>();
    BoxOfficeAdapter boxOfficeAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        boxoffice_recycler= findViewById(R.id.boxoffice_recycler);

        //Retrofit 객체생성
        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    /*addConverterFactory(GsonConverterFactory.create())은
    Json을 우리가 원하는 형태로 만들어주는 Gson라이브러리와 Retrofit2에 연결하는 코드입니다 */

        boxOfficeService = retrofit.create(BoxOfficeService.class);

        boxOfficeService.getBoxOffice(API_KEY, "20190608").enqueue(new Callback<Result>() {
            @Override
            public void onResponse(Call<Result> call, Response<Result> response) {
                if (response.isSuccessful()){
                    Log.d("retro", 1+"");
                    Result result = response.body();
                    BoxOfficeResult boxOfficeResult = result.getBoxOfficeResult();
                   List<WeeklyBoxOfficeList> weeklyBoxOfficeListLIst2 = boxOfficeResult.getWeeklyBoxOfficeList();
                   for (WeeklyBoxOfficeList weeklyBoxOffice : weeklyBoxOfficeListLIst2){
                       weeklyBoxOfficeLists.add(weeklyBoxOffice);
                   }

                   boxOfficeAdapter = new BoxOfficeAdapter(weeklyBoxOfficeLists, MainActivity.this);
                    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false);
                    boxoffice_recycler.setLayoutManager(linearLayoutManager);
                    boxoffice_recycler.setAdapter(boxOfficeAdapter);
                }else{
                    Log.d("retro", 2+"Error");
                }
            }

            @Override
            public void onFailure(Call<Result> call, Throwable t) {

            }
        });

    }
}

 

 

 

이제 실행을 하면 다음과같은 결과화면을 볼 수 있습니다.

딱히 보고싶은 영화는 없네요.. 어벤저스는이미봤구

 

이상 포스팅을 마치도록하겠습니다.

댓글과 공감은 큰힘이 됩니다. 감사합니다.

 

 

 

p.s) put방식

public interface MiniGramService {

    @GET("/minigrams")
    Call<List<MiniGram>> getMiniGram();

    //서버에 데이터를 수정해달라고 요청하는 메서드
     //"http://memolease.ipdisk.co.kr:1337/minigrams/id/{like:true}" 이런식으로 보내질거다.
    //그냥 String으로 보내면 서버에 put을 할수없어서 UTF-8로 바꿔서 보내야하는데 이를 레트로핏에서 FORMURLENCODED로 해준다.
    @FormUrlEncoded
    @PUT("/minigrams/{id}")
    Call<MiniGram> updateLike(@Path("id") String id, @Field("like") boolean like);
}
miniGramService.updateLike(heartEvent.getId(), heartEvent.isLike()).enqueue(new Callback<MiniGram>() {
            @Override
            public void onResponse(Call<MiniGram> call, Response<MiniGram> response) {
                if(response.isSuccessful()){
                    Log.d("like update", "sucess");
                }else{
                    Log.d("like update", "failed");
                }
            }

            @Override
            public void onFailure(Call<MiniGram> call, Throwable t) {
                Log.d("like update", "not connected");
            }
        });
728x90
Comments