
이번에 실습해본 내용은 Retrofit2을 이용하여 http://jsonplaceholder.typicode.com/photos 이곳에 있는 Api를 불러서 RecyclerView를 통해 데이터를 뿌려보았다.
1. 환경설정
Manifast Internet Permission 허용하기,
<uses-permission android:name="android.permission.INTERNET" />
app수준 buildgradle에 Okhttp, retrofit2, piccaso 권한 추가
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc03"
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.7.2'
implementation 'com.squareup.retrofit2:converter-gson:2.7.2'
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
여기서 picasso2는 https://~~ 형식으로 받아온 image 파일을 변환해주어 출력되도록 해주는 라이브러리이다.
2. 레이아웃 꾸미기
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">
<TextView
android:id="@+id/textViewEx"
android:layout_width="wrap_content"
android:layout_height="64dp"
android:text="레트로핏 실습"
android:textStyle="bold"
android:textSize="28sp"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/viewEx"
android:layout_width="match_parent"
android:layout_height="2px"
app:layout_constraintBottom_toBottomOf="@+id/textViewEx"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@color/purple_200"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyClerView"
android:layout_width="match_parent"
android:layout_height="0dp"
tools:listitem="@layout/recycler_view"
app:layout_constraintTop_toBottomOf="@id/viewEx"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:paddingTop="20px"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
recycler_view.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:id="@+id/frame_card"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_margin="20dp"
app:cardCornerRadius="10dp"
app:cardElevation="20dp">
<ProgressBar
android:id="@+id/progressBar"
android:layout_weight="1"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/iv_poster"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:background="@color/purple_200" />
<TextView
android:id="@+id/tv_text"
android:layout_width="230dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="벤자민 버튼의 시간은 거꾸로 간다."
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_poster"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_id"
android:layout_width="29dp"
android:layout_height="23dp"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="@+id/tv_text"
app:layout_constraintTop_toBottomOf="@+id/tv_text"
tools:text="9.9" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
</FrameLayout>
FrameLayout으로 감싼뒤 RelativeLayout에 cardview를 넣어준다. retrofi을 통해 api가 다 불러와지지 않을 경우를 대비해 progressbar를 통해 진행중 이라는 여부를 표시해준다.

3. Api 불러오기
이번 시간에 불러올 API는 http://jsonplaceholder.typicode.com/photos 이곳에서 가져와야 한다 총 500개의 Photo들이 있다.

ㅁ 위에서 보이는 json 모델들을 @SerializedName 를 통해 data class로 만들어준다.
package com.example.retrofitpractice.model
import com.google.gson.annotations.SerializedName
data class PhotoEntity(
@SerializedName("albumId") val albumId: Int,
@SerializedName("id") val id: Int,
@SerializedName("thumbnailUrl") val thumbnailUrl: String,
@SerializedName("title") val title: String,
@SerializedName("url") val url: String
)
ㅁ InterFaceRetrofit을 만들어준다.
package com.example.retrofitpractice.model
import retrofit2.Call
import retrofit2.http.GET
interface InterFaceRetrofit {
@GET("/photos")
fun listPhotos(): Call<List<PhotoEntity>>
}
PhotoEntity를 List로 담아서 Call을 지정해준다.
ㅁ Retrofit 통신을 위한 retrofitApi Object를 만들어준다.
package com.example.retrofitpractice.model
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object retrofitApi {
private const val BASE_URL = "https://jsonplaceholder.typicode.com/"
private val retrofit : Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val retrofitService : InterFaceRetrofit by lazy {
retrofit.create(InterFaceRetrofit::class.java)
}
}
이렇게 object로 따로 만들어준 이유는 Singleton 패턴을 이용하여 필요할때 한번 가져올 수 있도록 해야하기 때문이다.
1) 상수형태의 BASE_URL을 설정해준다
2) retrofit을 lazy로 Builder()를 선언해준다.
3) retofitSerce로 InterFaceRetrofit을 가져온다.
이렇게 하면 Api불러오는 설정은 다 끝났다.
4. mainActivity로 api 뿌려주기
package com.example.retrofitpractice
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.retrofitpractice.adapter.RecyclerViewAdapter
import com.example.retrofitpractice.databinding.ActivityMainBinding
import com.example.retrofitpractice.model.InterFaceRetrofit
import com.example.retrofitpractice.model.PhotoEntity
import com.example.retrofitpractice.model.retrofitApi
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MainActivity : AppCompatActivity() {
lateinit var adapter: RecyclerViewAdapter
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
adapter = RecyclerViewAdapter()
getPhotosListFromServer()
initRecyclerView()
}
private fun initRecyclerView() {
binding.recyClerView.adapter = adapter
binding.recyClerView.layoutManager = LinearLayoutManager(this)
}
private fun getPhotosListFromServer() {
val service = retrofitApi.retrofitService
service.listPhotos().enqueue(
object : Callback<List<PhotoEntity>> {
override fun onResponse(
call: Call<List<PhotoEntity>>,
response: Response<List<PhotoEntity>>
) {
if(response.isSuccessful == true){
val result = response.body()?.toList()
adapter.submitList(result!!)
}
}
override fun onFailure(call: Call<List<PhotoEntity>>, t: Throwable) {
Log.d("this", "실패 : ${t.toString()}")
}
}
)
}
}
InterFaseRetrofit에서 Call해준 <List<PohoEntity>>를 다시 callback 받아 response 해준다. 그리고 response.body()를 리스트에 담아서 oncreate에서 생성한 recyclerview adapter에 submitList를 통해 전달해준다.그러면 최종적으로 callback이 완료된다.
다음에는 공공데이터를 활용해 retrofit2을 불러오는 실습을 해봐야 겠다.
'안드로이드 > 정리(Android)' 카테고리의 다른 글
| Android - MotionLayout splash 앱 만들어보기 (0) | 2022.03.11 |
|---|---|
| kotlin - retrofit을 이용한 레시피 검색 앱 만들기 (0) | 2022.03.06 |
| Android - ViewPager2, RecyclerView , NavigationLayout 사용하기 (0) | 2022.03.03 |
| Android - firebase 채팅기능 사용 (0) | 2022.02.24 |
| Android - binding 사용하기 (0) | 2022.02.24 |