본문 바로가기
Android

안드로이드 레트로핏(Retrofit2)을 사용하여 주간 박스오피스 정보 불러오기

by Taron 2024. 4. 26.

안녕하세요 오늘 작성할 내용은 통신 라이브러리 Retrofit2이 무엇인지에 대해 알아보고 영화진흥위원회 API를 활용하여 데이터를 요청하고 받아오는 예제를 만들어 보겠습니다!!

 

레트로핏이란?

  • Square사에서 만든 HTTP 통신 라이브러리입니다.
  • OkHttp 라이브러리를 기반으로 만들어졌습니다.

레트로핏 장점

  • AsyncTask를 사용하여 OkHttp에 비해서 빠른 속도를 지원합니다.
  • Annotation을 사용하여 가독성이 좋습니다.
  • 동기 / 비동기를 지원합니다.

Retrofit2로 영화진흥위원회 API 사용하기


1. 라이브러리 의존성, 매니패스트 인터넷 권한 추가

https://github.com/square/retrofit

 

GitHub - square/retrofit: A type-safe HTTP client for Android and the JVM

A type-safe HTTP client for Android and the JVM. Contribute to square/retrofit development by creating an account on GitHub.

github.com

 

위 링크에 접속해 최신버전을 확인해 앱 수준의 그래들에 의존성을 추가합니다. 글 작성 당시 최신버전은 2.11.0이 최신버전이라 2.11.0 버전으로 진행하겠습니다. 

 

build.gradle.kts (앱 수준)

    // Retrofit2
    implementation ("com.squareup.retrofit2:retrofit:2.11.0")
    implementation( "com.squareup.retrofit2:converter-gson:2.11.0")

 

Manifast 파일에 인터넷 permission을 추가합니다.

 

AndroidManifast.xml

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

 

2. 모델 클래스를 만들기 위해 먼저 영화진흥위원회 API를 확인합니다.

먼저 API를 사용하기 위해 영화진흥위원회 홈페이지에 접속해 회원가입을 진행합니다.

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

 

영화진흥위원회 오픈API

OPEN API 서비스 영화진흥위원회 영화관입장권통합전산망에서 제공하는 오픈API 서비스로 더욱 풍요롭고 편안한 영화 서비스를 즐겨보세요.

www.kobis.or.kr

 

주간 박스오피스 데이터가 필요하기 때문에 주간 박스오피스 API 서비스로 들어가겠습니다.

요청 URL을 먼저 확인하고 요청 파라미터에 어떤 데이터가 필요한지 확인합니다.

 

위 파라미터를 기반으로 Interface를 만들어 주겠습니다.

ApiInterface.kt

package com.example.retrofit2_example

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

interface ApiInterface {
    @GET("boxoffice/searchWeeklyBoxOfficeList.json")
    fun getMovieList(
        @Query("key") key : String,
        @Query("targetDt") targetDt : String,
        @Query("weekGb") weekGb : String
    ): Call<ModelClass>
}

 

Response를 받아줄 Model 클래스도 만들어주겠습니다.

 

ModelClass.kt

package com.example.retrofit2_example

data class ModelClass(
    var boxOfficeResult: BoxOfficeResult
) {
    data class BoxOfficeResult(
        var boxofficeType: String,
        var showRange: String,
        var weeklyBoxOfficeList: List<WeeklyBoxOffice>,
        var yearWeekTime: String
    ) {
        data class WeeklyBoxOffice(
            var audiAcc: String,
            var audiChange: String,
            var audiCnt: String,
            var audiInten: String,
            var movieCd: String,
            var movieNm: String,
            var openDt: String,
            var rank: String,
            var rankInten: String,
            var rankOldAndNew: String,
            var rnum: String,
            var salesAcc: String,
            var salesAmt: String,
            var salesChange: String,
            var salesInten: String,
            var salesShare: String,
            var scrnCnt: String,
            var showCnt: String
        )
    }
}

 

위 클래스는 영화진흥위원회 API에 응답 파라미터를 기준으로 만들어야 합니다.

모델 클래스와 요청 인터페이스를 만들었으니 한번 요청을 보내보도록 하겠습니다.

 

MainActivity.kt

package com.example.retrofit2_example

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class MainActivity : AppCompatActivity() {
    private val TAG = "MainActivity"
    private val BASE_URL = "http://www.kobis.or.kr/kobisopenapi/webservice/rest/"
    private val key = "영화진흥위원회에서 발급받는 키"
    private lateinit var retrofit: Retrofit

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        init()

        getMovie()
    }
    private fun init(){
        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    private fun getMovie(){
        retrofit.create(ApiInterface::class.java).getMovieList(key,"20240420","0").enqueue(
            object : Callback<ModelClass>{
                override fun onResponse(call: Call<ModelClass>, response: Response<ModelClass>) {
                    if(response.isSuccessful) {
                        Log.d(TAG, "onResponse: ${response.body()?.boxOfficeResult}")
                    }
                }

                override fun onFailure(p0: Call<ModelClass>, p1: Throwable) {
                    Log.d(TAG, "요청 실패 : $p1")
                }

            }
        )
    }

}

 

위 코드를 실행 시켰을때 아래와 같은 결과를 확인 할 수 있습니다.

 

2024-04-26 20:48:08.090  6445-6445  MainActivity            com.example.retrofit2_example        D  onResponse: BoxOfficeResult(boxofficeType=주간 박스오피스, showRange=20240415~20240421, weeklyBoxOfficeList=[WeeklyBoxOffice(audiAcc=1248303, audiChange=-57.6, audiCnt=370571, audiInten=-504361, movieCd=20236614, movieNm=쿵푸팬더4, openDt=2024-04-10, rank=1, rankInten=0, rankOldAndNew=OLD, rnum=1, salesAcc=11681285845, salesAmt=3443394942, salesChange=-58.1, salesInten=-4767261961, salesShare=37.7, scrnCnt=1533, showCnt=34193), WeeklyBoxOffice(audiAcc=11785099, audiChange=-38.6, audiCnt=171009, audiInten=-107358, movieCd=20234675, movieNm=파묘, openDt=2024-02-22, rank=2, rankInten=0, rankOldAndNew=OLD, rnum=2, salesAcc=113914246413, salesAmt=1689456118, salesChange=-38.6, salesInten=-1062648304, salesShare=18.5, scrnCnt=1053, showCnt=18717), WeeklyBoxOffice(audiAcc=386880, audiChange=-43.1, audiCnt=65289, audiInten=-49441, movieCd=20231677, movieNm=남은 인생 10년, openDt=2023-05-24, rank=3, rankInten=1, rankOldAndNew=OLD, rnum=3, salesAcc=3952099130, salesAmt=652200364, salesChange=-43.2, salesInten=-496126546, salesShare=7.1, scrnCnt=529, showCnt=7203), WeeklyBoxOffice(audiAcc=963871, audiChange=-58.5, audiCnt=48168, audiInten=-67812, movieCd=20231041, movieNm=댓글부대, openDt=2024-03-27, rank=4, rankInten=-1, rankOldAndNew=OLD, rnum=4, salesAcc=9158023810, salesAmt=470920646, salesChange=-58.9, salesInten=-673545496, salesShare=5.2, scrnCnt=631, showCnt=7791), WeeklyBoxOffice(audiAcc=36960, audiChange=19671.0, audiCnt=36774, audiInten=36588, movieCd=20248466, movieNm=고스트버스터즈: 오싹한 뉴욕, openDt=2024-04-17, rank=5, rankInten=59, rankOldAndNew=OLD, rnum=5, salesAcc=348915020, salesAmt=347241020, salesChange=20643.2, salesInten=345567020, salesShare=3.8, scrnCnt=671, showCnt=7567), WeeklyBoxOffice(audiAcc=174052, audiChange=-52.7, audiCnt=28406, audiInten=-31634, movieCd=20247673, movieNm=오멘: 저주의 시작, openDt=2024-04-03, rank=6, rankInten=-1, rankOldAndNew=OLD, rnum=6, salesAcc=1789740877, salesAmt=295875931, salesChange=-52.5, salesInten=-326674475, salesShare=3.2, scrnCnt=427, showCnt=3877), WeeklyBoxOffice(audiAcc=28253, audiChange=100.0, audiCnt=28253, audiInten=28253, movieCd=20228797, movieNm=범죄도시4, openDt=2024-04-24, rank=7, rankInten=0, rankOldAndNew=NEW, rnum=7, salesAcc=326042800, salesAmt=326042800, salesChange=100.0, salesInten=326042800, salesShare=3.6, scrnCnt=24, showCnt=163), WeeklyBoxOffice(audiAcc=1987130, audiChange=-23.6, audiCnt=20303, audiInten=-6286, movieCd=20236295, movieNm=듄: 파트2, openDt=2024-02-28, rank=8, rankInten=0, rankOldAndNew=OLD, rnum=8, salesAcc=23287956313, salesAmt=261810792, salesChange=-20.8, salesInten=-68768771, salesShare=2.9, scrnCnt=188, showCnt=1572), WeeklyBoxOffice(audiAcc=506726, audiChange=-64.4, audiCnt=14929, audiInten=-27055, movieCd=20248496, movieNm=고질라 X 콩: 뉴 엠파이어, openDt=2024-03-27, rank=9, rankInten=-3, rankOldAndNew=OLD, rnum=9, salesAcc=5076739231, salesAmt=144696681, salesChange=-64.7, salesInten=-264954213, salesShare=1.6, scrnCnt=303, showCnt=2522), WeeklyBoxOffice(audiAcc=16986, audiChange=546.3, audiCnt=14710, audiInten=12434, movieCd=20235613, movieNm=스턴트맨, openDt=2024-05-01, rank=10, rankInten=14, rankOldAndNew=OLD, rnum=10, salesAcc=157866000, salesAmt=137382000, salesChange=570.7, salesInten=116898000, salesShare=1.5, scrnCnt=35, showCnt=71)], yearWeekTime=202416)

 

이제 받아온 데이터를 리사이클러뷰에 띄어주고 마치겠습니다.

 

item.xml

<?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="wrap_content"
    android:layout_margin="10dp"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/rank"
        android:layout_width="70dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="1위" />

    <TextView
        android:id="@+id/movieNm"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="영화이름" />

    <TextView
        android:id="@+id/openDt"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="YYYY-MM-DD" />
</LinearLayout>

 

Adapters.kt

package com.example.retrofit2_example

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class Adapters (var itemList: List<ModelClass.BoxOfficeResult.WeeklyBoxOffice>) : RecyclerView.Adapter<Adapters.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        Log.d("ddd", "onBindViewHolder: ${itemList[position]}")
        holder.tvRank.text = itemList[position].rank
        holder.tvNm.text = itemList[position].movieNm
        holder.tvDt.text = itemList[position].openDt
    }

    override fun getItemCount(): Int {
        return itemList.count()
    }

    fun setList(list : List<ModelClass.BoxOfficeResult.WeeklyBoxOffice>){
        itemList = list
        notifyDataSetChanged()
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tvNm = itemView.findViewById<TextView>(R.id.movieNm)
        val tvRank = itemView.findViewById<TextView>(R.id.rank)
        val tvDt = itemView.findViewById<TextView>(R.id.openDt)
    }
}

 

MainActivity.kt

package com.example.retrofit2_example

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class MainActivity : AppCompatActivity() {
    private val TAG = "MainActivity"
    private val BASE_URL = "http://www.kobis.or.kr/kobisopenapi/webservice/rest/"
    private val key = "영화진흥위원회에서 발급한 키"
    private lateinit var retrofit: Retrofit
    private lateinit var recyclerView: RecyclerView
    private lateinit var list : List<ModelClass.BoxOfficeResult.WeeklyBoxOffice>
    private lateinit var adapter : Adapters

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        init()

        getMovie()
    }
    private fun init(){
        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        list = ArrayList()

        adapter = Adapters(list)

        recyclerView = findViewById(R.id.recyclerview)
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
    }


    private fun getMovie(){
        retrofit.create(ApiInterface::class.java).getMovieList(key,"20240420","0").enqueue(
            object : Callback<ModelClass>{
                override fun onResponse(call: Call<ModelClass>, response: Response<ModelClass>) {
                    if(response.isSuccessful) {
                        if(response.body()?.boxOfficeResult?.weeklyBoxOfficeList != null){
                            list = response.body()?.boxOfficeResult?.weeklyBoxOfficeList!!
                            adapter.setList(list)
                        }
                    }
                }

                override fun onFailure(p0: Call<ModelClass>, p1: Throwable) {
                    Log.d(TAG, "요청 실패 : $p1")
                }

            }
        )
    }

}

 

위 코드를 실행 한 후 결과 화면

 

이상 레트로핏에 대해 작성해봤는데요. 레트로핏을 공부하는분들에게 도움이 되었으면 합니다. 감사합니다

'Android' 카테고리의 다른 글

안드로이드 Compose란 + 예제  (0) 2024.03.05
안드로이드 DataBinding 사용 예제  (0) 2024.03.04
안드로이드 ROOM 사용법 + 예제  (0) 2024.03.03
Hilt 란?  (0) 2024.02.06
WebRTC 란?  (2) 2023.08.08

댓글