Retrofit으로 통신해보기

상환·2021년 10월 5일
0

안드로이드 공부

목록 보기
7/7
post-thumbnail

소개

Retrofit2는 안드로이드 REST API 통신 라이브러리입니다. 통신 라이브러리중 Volley와 함께 가장 많이 사용되는 라이브러리입니다.
Retrofit을 사용한 이유는 성능과 간단한 구현, Type-Safe때문입니다.
소개는 여기까지하고 바로 구현으로 들어가겠습니다.

구현

Retrofit을 사용하려면 세 가지 클래스가 필요합니다.

  1. JSON형태의 모델클래스
  2. HTTP 작업을 정의하는 (onSuccess/onFail) 인터페이스
  3. Retrofit.Builder를 선언한 클래스(baseUrl과 Converter등을 선언, Interceptor를 추가하여 응답을 가공할 수도 있다.)

1. Empty Activity생성. (API Level 30)

2. build.gradle 수정

Retrofit, Picasso, Gson의 의존성을 추가합니다.

dependencies{
    //의존성 추가
    implementation 'com.squareup.picasso:picasso:2.5.2'
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
}

3. AndroidManifest.xml 수정

Manifest에서 Internet도 허용해줍니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.retrofittest">

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

    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.RetrofitTest">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

4. BaseUrl 확인

가져올 JSON은 https://jsonplaceholder.typicode.com/photos 입니다.

[
  {
    "albumId": 1,
    "id": 1,
    "title": "accusamus beatae ad facilis cum similique qui sunt",
    "url": "https://via.placeholder.com/600/92c952",
    "thumbnailUrl": "https://via.placeholder.com/150/92c952"
  },
  {
    "albumId": 1,
    "id": 2,
    "title": "reprehenderit est deserunt velit ipsam",
    "url": "https://via.placeholder.com/600/771796",
    "thumbnailUrl": "https://via.placeholder.com/150/771796"
  }
...

요청을 위해 dataClass를 model패키지에 정의합니다.

package com.example.retrofittest.model

import com.google.gson.annotations.SerializedName

//데이터 통신을 위한 모델클래스 생성
data class RetroPhoto(
    @SerializedName("albumId")      var albumId: Int,
    @SerializedName("id")           var id: Long,
    @SerializedName("title")        var title: String,
    @SerializedName("url")          var url: String,
    @SerializedName("thumbnailUrl") var thumbnailUrl: String,
){

}

5. Retrofit Instance를 network패키지에 정의

REST API에 요청하기위해 Retrofit.Builder클래스와 baseUrl을 정의한 인스턴스를 사용합니다.

package com.example.retrofittest.network

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.*

//레트로핏 인스턴스 생성
class RetrofitClientInstance {
    companion object{
        private val BASE_URL: String = "https://jsonplaceholder.typicode.com"
    }

    fun getRetrofitInstance(): Retrofit{
        var retrofit = retrofit2
        .Retrofit
        .Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create()).build()!!
        return retrofit
    }
}

6. EndPoints설정

service패키지 GetDataService interface를 정의합니다.

package com.example.retrofittest.service

import com.example.retrofittest.model.RetroPhoto
import retrofit2.Call
import retrofit2.http.GET

//엔드포인트 설정
interface GetDataService {
    @GET("/photos")
    fun getAllPhoto(): Call<List<RetroPhoto>>
}

7. Adapter 정의

RecyclerView에 뿌려주기위해 adapter패키지에 CustomAdapter를 정의합니다.

package com.example.retrofittest.adapter

import android.content.Context
import android.text.Layout
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.retrofittest.R
import com.example.retrofittest.model.RetroPhoto
import com.jakewharton.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso

class CustomAdapter(var context: Context, var dataList: List<RetroPhoto>) : RecyclerView.Adapter<CustomAdapter.CustomViewHolder>() {
    //뷰홀더 생성
    inner class CustomViewHolder(val itemView: View) : RecyclerView.ViewHolder(itemView){
        var txtTitle : TextView= itemView.findViewById(R.id.title)
        var coverImage : ImageView = itemView.findViewById(R.id.coverImage)
    }

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

    override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
        holder.txtTitle.setText(dataList[position].title)

        //Picasso라이브러리를 이용하여 ImageView에 간단하게 이미지 로딩
        val builder = Picasso.Builder(context)
        builder.downloader(OkHttp3Downloader(context))
        builder.build().load(dataList[position].thumbnailUrl)
            .placeholder((R.drawable.ic_launcher_background))
            .error(R.drawable.ic_launcher_background)
            .into(holder.coverImage)
    }

    override fun getItemCount(): Int = dataList.size
}

8. MainActivity

MainActivity에서 요청, 응답수행후 callBack에서 아이템뷰를 만들어줍니다.

package com.example.retrofittest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.retrofittest.adapter.CustomAdapter
import com.example.retrofittest.model.RetroPhoto
import com.example.retrofittest.service.GetDataService
import com.example.retrofittest.network.RetrofitClientInstance
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        //서비스 호출
        val service: GetDataService = RetrofitClientInstance().getRetrofitInstance().create(GetDataService::class.java)
        //콜백 정의
        val call: Call<List<RetroPhoto>> = service.getAllPhoto()

        call.enqueue(object: Callback<List<RetroPhoto>>{
            override fun onResponse(call: Call<List<RetroPhoto>>, response: Response<List<RetroPhoto>>) {
                generateDataList(response.body()!!)
            }

            override fun onFailure(call: Call<List<RetroPhoto>>, t: Throwable) {
                Toast.makeText(applicationContext, "SomeThing went wrong...Plase try later!", Toast.LENGTH_SHORT).show()
            }

        })
    }

    private fun generateDataList(photoList: List<RetroPhoto>) {
        val recycler: RecyclerView = findViewById(R.id.customRecyclerView)
        val layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(applicationContext)
        recycler.layoutManager = layoutManager
        recycler.adapter = CustomAdapter(this, photoList)
    }
}

레이아웃

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

    <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/customRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

    <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
    >

        <ImageView
                android:id="@+id/coverImage"
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:layout_alignParentTop="true"
                android:scaleType="centerCrop"/>

        <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@+id/coverImage"
                android:layout_marginLeft="16dp"
                android:paddingTop="20dp"
                android:lines="2"
                android:text="title"/>

    </RelativeLayout>


</androidx.cardview.widget.CardView>
custom_row.xml

결과


위 사진처럼 정상적으로 뷰가 생성된 것을 확인할 수 있습니다.

참고

Retrofit-A simple Android tutorial
SAM을 사용하는 방법
Retrofit이란?

profile
레모네이드 커피

0개의 댓글