유니 코드

[Android/Kotlin] 도서 리뷰 앱 - Retorfit으로 API 호출하기 본문

오늘의 공부는?!/Android

[Android/Kotlin] 도서 리뷰 앱 - Retorfit으로 API 호출하기

꼬물쥰 2022. 6. 29. 19:10

recyclerview로 도서목록 출력

 

이번 글은 Retrofit으로 api를 호출하고 recyclerview를 활용해 정보를 띄워주는 기능을 구현하려고 한다

API는 Naver에서 제공하는 검색 API(도서)를 사용했다

 

  • MainActivity.kt에서 Retrofit 객체 생성

앞에서 만들었던 인터페이스는 어떻게 사용을 할지 정의만 해놓은 것이기 때문에

액티비티에서 구현해주어야 한다.

val CLIENT_ID = "clientId"
val CLIENT_SECRET = "clientSecret"
val BASE_URL_NAVER_API = "https://openapi.naver.com"

val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL_NAVER_API)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val bookService = retrofit.create(BookService::class.java)

우선 clientId와 clientSecret, baseUrl을 val 변수로 선언한다

 

retrofit 객체를 생성할 때는 먼저 어떤 서버에 요청을 보낼지 baseUrl()에 넘겨준다

addConverterFactory()는 데이터를 파싱할 converter를 추가하는 메서드로 우리는 gsonConverter를 이용한다

 

이렇게 만들어진 Retrofit 객체를 이용해 Interface를 구현해준다

 

 

  • HTTP 요청과 응답
private fun search(keyword: String){
    bookService.getBooksByName(CLIENT_ID, CLIENT_SECRET, keyword)
        .enqueue(object: Callback<SearchDto>{
            override fun onResponse(call: Call<SearchDto>, response: Response<SearchDto>) {
                if(response.isSuccessful().not()){
                    return
                }
                adapter.submitList(response.body()?.books.orEmpty())
            }
            override fun onFailure(call: Call<SearchDto>, t: Throwable) {
                Log.e(TAG, t.toString())
            }
        })
}

도서를 검색할 때 호출할 search함수를 만들어보자

인자는 String형의 keyword로 준다

bookService에서 사용할 수 있는 메소드를 하나 정의해뒀으니 그걸 사용해준다

getBooksByName의 인자는 clientId, clientSecret, keyword이다

비동기로 통신을 요청하기 위해 enqueue를 사용한다 (동기는 execute)

private fun search(keyword: String){
    bookService.getBooksByName(CLIENT_ID, CLIENT_SECRET, keyword)
        .enqueue(object: Callback<SearchDto>{
            override fun onResponse(call: Call<SearchDto>, response: Response<SearchDto>) { 
                if(response.isSuccessful().not()){
                    return
                }
                adapter.submitList(response.body()?.books.orEmpty())
            }
            override fun onFailure(call: Call<SearchDto>, t: Throwable) {
                Log.e(TAG, t.toString())
            }
        })
}

요청을 보낸 후 결과는 통신 성공과 통신 실패로 나뉜다

성공했을 경우에는 onResponse

실패했을 경우에는 onFailure

private fun search(keyword: String){
    bookService.getBooksByName(CLIENT_ID, CLIENT_SECRET, keyword)
        .enqueue(object: Callback<SearchDto>{
            override fun onResponse(call: Call<SearchDto>, response: Response<SearchDto>) { 
                if(response.isSuccessful().not()){
                    return
                }
                adapter.submitList(response.body()?.books.orEmpty())
            }
            override fun onFailure(call: Call<SearchDto>, t: Throwable) {
                Log.e(TAG, t.toString())
            }
        })
}

 

 

  • Activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/searchEditText"
        android:layout_width="0dp"
        android:lines="1"
        android:inputType="text"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/searchEditText"
        app:layout_constraintBottom_toBottomOf="parent"
        android:id="@+id/bookRecyclerView"/>


</androidx.constraintlayout.widget.ConstraintLayout>

메인 xml 화면 상단에는 검색어를 입력할 editText를 추가해주고

그 아래는 recyclerView를 추가해준다

 

  • item_book.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools"
    android:padding="16dp">

    <ImageView
        android:padding="8dp"
        android:id="@+id/coverImageView"
        android:layout_width="85dp"
        android:layout_height="100dp"
        android:background="@drawable/background_gray_stroke_radius_16"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/titleTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/coverImageView"
        tools:text="안드로이드 마스터하기"
        android:lines="1"
        android:ellipsize="end"
        android:textSize="16sp"
        android:textColor="@color/black"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginLeft="12dp" />

    <TextView
        android:id="@+id/descriptionTextView"
        android:maxLines="3"
        android:textSize="12sp"
        android:ellipsize="end"
        android:layout_marginTop="12dp"
        app:layout_constraintTop_toBottomOf="@id/titleTextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="@id/titleTextView"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_width="0dp"
        android:layout_height="0dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

메인 xml에 있는 recyclerView에 들어갈 xml이다

책 이미지가 들어갈 imageView와 도서이름과 설명이 들어갈 textView를 2개 만들어주었다

 

recyclerView를 사용하기 위해서는 layoutManager와 adapter가 필요한데

다음 글에 이어서 설명하겠다 :)

Comments