김호쭈
DevForYou
김호쭈
전체 방문자
오늘
어제
  • 분류 전체보기 (321)
    • • 데이터베이스(DB) (9)
      • __SQL__ (9)
    • •알고리즘(Algorithm ) (117)
      • 문제풀이 (99)
      • 스터디 (14)
      • 알고리즘 팁 (4)
    • •Compter Science (57)
      • Operating System (25)
      • Computer Network (1)
      • Computer Vision (16)
      • Artificial Intelligence (14)
      • Software Technology (1)
    • • 독서 (36)
      • Design Pattern (24)
      • 객체지향의 사실과 오해 (1)
      • Object Oriented Software En.. (11)
    • • 개발 (26)
      • React (3)
      • node.js (6)
      • Django (11)
      • Spring boot (6)
    • • 개발Tip (4)
      • GitHub (0)
    • •프로젝트 (2)
      • 물물 (2)
    • •App (54)
      • 안드로이드 with Kotlin (50)
      • 코틀린(Kotiln) (4)
    • •회고 (8)
    • •취준일기 (3)
    • • 기타 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • ㄱ
  • 원격저장소
  • GitHubDesktop
  • 깃허브데스크탑
  • local저장소
  • Remote저장소
  • KMU_WINK
  • 로컬저장소

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
김호쭈

DevForYou

[안드로이드&코틀린] 에어비앤비#2, Mocky로 임시 API 만들기, Glide에서 CenterCrop사용하기, Glide로 corner radius주기 ,dp값 px로 바꾸기
•App/안드로이드 with Kotlin

[안드로이드&코틀린] 에어비앤비#2, Mocky로 임시 API 만들기, Glide에서 CenterCrop사용하기, Glide로 corner radius주기 ,dp값 px로 바꾸기

2022. 7. 4. 23:56
 

[안드로이드&코틀린] 에어비앤비#1, 네이버 mapAPI 사용하기, 코디네이터(CoordinatorLayout)레이아웃, bo

에어비앤비와 유사한 앱을 만들어보았다. BottomSheetDialog 역할을 하는 view와 네이버 mapAPI, viewpager2등을 사용했다. 무엇보다 안드로이드 실제 디바이스를 당근마켓에서 구입해서 하고있는데, 빠릿

devforyou.tistory.com

이번에는 간단하게 테스트용 API를 Json형식으로 만든 후 사용하는 방법과, 글라이드와 레트로핏을 사용하여 받아오는걸 해보도록 하겠다.

 

# Mocky

아래 페이지에 들어간다.

 

Mocky: The world's easiest & fastest tool to mock your APIs

 

designer.mocky.io

NEW MOCK을 클릭하고, 난 API요청(GET)을 보내 정보를 받아올거이기 때문에 Response Body에 받아올 데이터를 미리 만들어 붙여넣으면 api주소를 주는데 그곳에서 내가 작성했던 내용 그대로를 response로 보내준다. 

아래와 같이 json형식으로 mock을 만들어주자.

{
  "items" : [
    {
      "id" : 1,
      "title" : "강남역 주변, COZY한 집",
      "price" : "50,000원",
      "lat" : 37.4978028,
      "lng" : 127.0282324,
      "imgUrl" : "https://loremflickr.com/cache/resized/65535_51753613651_7e4eeca87b_n_200_200_nofilter.jpg"
    },
    {
      "id" : 2,
      "title" : "강남역 주변, 편안한 집",
      "price" : "50,000원",
      "lat" : 37.497156,
      "lng" : 127.027267,
      "imgUrl" : "https://loremflickr.com/cache/resized/65535_51519263196_8529f860f7_n_200_200_nofilter.jpg"
    },
    {
      "id" : 3,
      "title" : "강남역 주변, 나쁜 집",
      "price" : "40,000원",
      "lat" : 37.4982113,
      "lng" : 127.0267947,
      "imgUrl" : "https://loremflickr.com/cache/resized/65535_51753613651_7e4eeca87b_n_200_200_nofilter.jpg"
    },
    {
      "id" : 4,
      "title" : "강남역 주변, 착한 집",
      "price" : "20,000원",
      "lat" : 37.496892,
      "lng" : 127.0296915,
      "imgUrl" : "https://loremflickr.com/cache/resized/65535_51488712625_59d63bc8b5_m_200_200_nofilter.jpg"
    },
    {
      "id" : 5,
      "title" : "강남역 주변, 좋은 집",
      "price" : "30,000원",
      "lat" : 37.4999988,
      "lng" : 127.0291014,
      "imgUrl" : "https://loremflickr.com/cache/resized/65535_52111075718_324aff5091_m_200_200_nofilter.jpg"
    }
  ]
}

 

# 레트로핏, 글라이더 사용

//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

//glide
implementation 'com.github.bumptech.glide:glide:4.13.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'

늘 하던대로 retrofit과 glide를 추가해준다. 이번에 SW중심대학 해커톤에서 레트로핏을 주구장창 사용해서 꽤 익숙해져 버렸다.. 

// MainActivity.kt

// create Retrofit
retrofit = Retrofit.Builder()
    .baseUrl("https://run.mocky.io/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
private fun getHouseDataAPI() {
    startProgressbar()
    retrofitService = retrofit.create(RetrofitService::class.java)
    retrofitService.getHouseData().enqueue(object : Callback<HouseDto>{
        override fun onResponse(call: Call<HouseDto>, response: Response<HouseDto>) {
            if(response.isSuccessful.not()) {
                Toast.makeText(this@MainActivity,"데이터 응답 실패",Toast.LENGTH_SHORT).show()
                return
            }
        }

        override fun onFailure(call: Call<HouseDto>, t: Throwable) {
            // 실패 처리
        }
    })
}

레트로핏을 build해주고, 레트로핏서비스를 만들어줘야 한다. 레트로핏 서비스 인터페이스에서는 GET,POST등과의 요청 및 url 그리고 어떤 데이터를 받아오는지를 알려주는 역할을 한다.

// RetrofitService.kt

interface RetrofitService {
    @GET("여기에 baseURL뒤의 주소를 입력")
    fun getHouseData() : Call<HouseDto> //응답받는 데이터 DTO
}

아까 우리가 작성한 Mock API에서 items : [...] 안에 정보를 담아 보내줬다. 

//HouseDto.kt

data class HouseDto(
    @SerializedName("items") val items : List<HouseData>
)

// HouseData.kt

data class HouseData(
    @SerializedName("id") val id : Int,
    @SerializedName("title") val title : String,
    @SerializedName("price") val price : String,
    @SerializedName("lat") val lat : Double,
    @SerializedName("lng") val lng : Double,
    @SerializedName("imgUrl") val imgUrl : String,
)

그리고 그렇게 받아온 리스트 안에는 HouseData안에 있는것들을 최종 사용하게 될 것이다. 

 

# ViewPager2 어댑터

자세한 코드 설명은 생략하도록 하겠다. 

class HouseViewPagerAdapter(val pageClickedCallback : (HouseData)-> Unit) : ListAdapter<HouseData, HouseViewPagerAdapter.ItemViewHolder>(differ){
    inner class ItemViewHolder(val view : View) : RecyclerView.ViewHolder(view){
        fun bind(house : HouseData){
            val title = view.findViewById<TextView>(R.id.titleTextView)
            val price = view.findViewById<TextView>(R.id.priceTextView)
            val image = view.findViewById<ImageView>(R.id.thumbnailImageView)

            view.setOnClickListener {
                pageClickedCallback(house)
            }

            title.text = house.title
            price.text = house.price
            Glide.with(image.context)
                .load(house.imgUrl)
                .into(image)
        }
    }

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

    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        holder.bind(currentList[position])
    }

    companion object {
        val differ = object : DiffUtil.ItemCallback<HouseData>(){
            override fun areItemsTheSame(oldItem: HouseData, newItem: HouseData): Boolean {
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: HouseData, newItem: HouseData): Boolean {
                return oldItem == newItem
            }

        }
    }
}

 

# 리사이클러뷰 어댑터

class HouseRecyclerViewApdater : ListAdapter<HouseData, HouseRecyclerViewApdater.ItemViewHolder>(differ){
    inner class ItemViewHolder(val view : View) : RecyclerView.ViewHolder(view){
        fun bind(house : HouseData){
            val title = view.findViewById<TextView>(R.id.titleTextView)
            val price = view.findViewById<TextView>(R.id.priceTextView)
            val image = view.findViewById<ImageView>(R.id.thumbnailImageView)

            title.text = house.title
            price.text = house.price
            // centerCrop -> 비트맵을 수정후 view에 그림
            // 겉 부분 둥글게 하는법, 기본단위 px이기때문에 px-> DP 로 바꿔야함
            Glide.with(image.context)
                .load(house.imgUrl)
                .transform(CenterCrop(), RoundedCorners(dpToPx(image.context,12)))
                .into(image)
        }
    }

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

    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        holder.bind(currentList[position])
    }

    private fun dpToPx(context: Context, dp:Int) : Int {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp.toFloat(),context.resources.displayMetrics).toInt()

    }

    companion object {
        val differ = object : DiffUtil.ItemCallback<HouseData>(){
            override fun areItemsTheSame(oldItem: HouseData, newItem: HouseData): Boolean {
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: HouseData, newItem: HouseData): Boolean {
                return oldItem == newItem
            }

        }
    }
}

리사이클러뷰에서는 받아온 이미지에 radius와 꽉차게 해줘야 한다. Glide의 transform속성을 이용하면 쉽게 바꿔 줄 수 있다. 

.transform(CenterCrop(), RoundedCorners(dpToPx(image.context,12)))

RoundedCorners를 통해서 radius값을 줄 수 있는데, 대신 기본 px값으로 설정이 되기때문에 기기마다 다른 크기가 잡힐 것이다. 그렇기 때문에 dp를 px로 바꿔주는 함수를 따로 작성해 사용한다. 

    private fun dpToPx(context: Context, dp:Int) : Int {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp.toFloat(),context.resources.displayMetrics).toInt()

    }

 

# Adpater 연동

 작성한 어댑터들을 뷰의 어댑터 속성에 할당해주고, submit이 필요한 지점에 알맞게 submitList를 해준다.

housePageApdater.submitList(dto.items)
houseRecyclerViewApdater.submitList(dto.items)

 

# 끝내며 

 Mocky는 아주 유용하게 쓸 수 있을 것 같다. 이번 에어비앤비 비스무리하게 만드는 프로젝트에서는 딱히 어려운 기능이 별로 없는거 같다. 아키텍처 공부하려고 책도 샀는데 얼른 아키텍처 공부하고 싶다.

 이번에 SW중심대학 해커톤 참가해서 상탔는데 그것도 블로그에 후딱 정리해야하 겠다.

저작자표시 (새창열림)

'•App > 안드로이드 with Kotlin' 카테고리의 다른 글

[안드로이드&코틀린] 유튜브#1, 모션레이아웃(MotionLayout)을 통해 스와이프 구현, 레이아웃 스와이프, 유튜브 플레이어, 프래그먼트, 프레임레이아웃  (0) 2022.07.06
[안드로이드&코틀린] 에어비앤비#3, 공유하기 기능, 마커 클릭시 viewPager전환, viewPager전환시 마커 표시, locationButton, 위치 권한 받기  (1) 2022.07.05
[안드로이드&코틀린] 에어비앤비#1, 네이버 mapAPI 사용하기, 코디네이터(CoordinatorLayout)레이아웃, bottomSheet레이아웃 만들기  (0) 2022.07.04
[에러/안드로이드] 액티비티간 주고받은 uri 권한 연장하기, Permission Denial: opening provider com.android.providers.media.MediaDocumentProvider  (0) 2022.05.25
[안드로이드&코틀린] 앨범 만들기#5, 파이어베이스 스토리지 사용하기, 코틀린 콜백함수, 이미지 업로드하기, 이미지 불러오기, 프로그레스 바, 안드로이드 화면 터치 막기  (0) 2022.05.11
    '•App/안드로이드 with Kotlin' 카테고리의 다른 글
    • [안드로이드&코틀린] 유튜브#1, 모션레이아웃(MotionLayout)을 통해 스와이프 구현, 레이아웃 스와이프, 유튜브 플레이어, 프래그먼트, 프레임레이아웃
    • [안드로이드&코틀린] 에어비앤비#3, 공유하기 기능, 마커 클릭시 viewPager전환, viewPager전환시 마커 표시, locationButton, 위치 권한 받기
    • [안드로이드&코틀린] 에어비앤비#1, 네이버 mapAPI 사용하기, 코디네이터(CoordinatorLayout)레이아웃, bottomSheet레이아웃 만들기
    • [에러/안드로이드] 액티비티간 주고받은 uri 권한 연장하기, Permission Denial: opening provider com.android.providers.media.MediaDocumentProvider
    김호쭈
    김호쭈
    공부하고 정리하고 기록하기

    티스토리툴바