[Kotlin] RecyclerView: retrofit2 GET 서버 연동

오송아·2021년 4월 27일
0
post-thumbnail

📌 Retrofit2이란?

안드로이드에서 API 서버와 통신하기 위한 방법으로 HttpUrlConnection, Volley, OkHttp, Retrofit2 등이 존재합니다. 그중에서 Retrofit2는 구현하기 쉽고 성능과 가독성이 좋다는 장점을 가지고 있습니다.

📌 Retrofit2를 이용 방법은?

👉 Retrofit2 라이브러리 추가

implementation 'com.squareup.retrofit2:retrofit:버전정보'
implementation 'com.squareup.retrofit2:converter-gson:버전정보'

build.gradle 파일에 retrofit2 라이브러리를 추가해줍니다.

👉 GitHub Wiki를 보고 Data Class인 ResponseCertiTab 생성

data class ResponseCertiTab(
    val `data`: List<Data>,
    val message: String,
    val status: Int,
    val success: Boolean
)
{
    data class Data(
        val id: Int,
        val image: String,
        val user_id: Int,
        val user_img: String,
        val user_name: String
    )
}

JSON 데이터를 받아올 ResponseCertiTab라는 Data Class를 생성해줍니다. 여기서는 GET /certi/:userName?date로 api를 가져오며 Request Query는 date, Response의 Data는 list 형식입니다.

👉 Interface인 CertifRetrofitService 생성

interface CertifRetrofitService {
    @GET("/certi/{userName}")
    fun requestList(
        @Path("userName") userName: String,
        @Query("date") date: String
    ) : Call<ResponseCertiTab>
}

API 인터페이스를 생성 후 어노테이션을 이용하여 HTTP Method인 POST, GET, PUT, DELETE를 설정해줍니다.

👉 Object 파일인 service_ct_tab 생성

object GroupRetrofitServiceImpl {
    private const val BASE_URL = "http://15.164.186.213:3000/"

    private val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    //인증탭 - 메인
    val service_ct_tab : CertifRetrofitService = retrofit.create(CertifRetrofitService::class.java)
}

코틀린의 object 키워드를 이용하여 싱글톤으로 생성해줍니다. baseUrl에는 연동할 서버 url을 넣어주며, addConverterFactory에는 GsonConverter를 추가하여 JSON 형식을 Data Class 형식으로 자동변환해줍니다.

👉 서버 연동을 원하는 뷰에서 certiList 변수 선언

class CertifTabFragment : Fragment() {

    @RequiresApi(Build.VERSION_CODES.O)
    @SuppressLint("ResourceType", "SetTextI18n")

    var data: ResponseCertiTab? = null
    var certiList: List<ResponseCertiTab.Data>? = null

    private lateinit var recyclerView: RecyclerView
    private lateinit var viewAdapter: RecyclerView.Adapter<*>
    private lateinit var viewManager: RecyclerView.LayoutManager

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_certif_tab, container, false)
        load(serverDate)

        return view
    }

ResponseCertiTab의 타입인 data와 certiList 변수를 선언해줍니다.

👉 loadData 메소드를 만들어 retrofit2 연동

    private fun load(serverDate: String){
        //Callback 등록하여 통신 요청
        val call: Call<ResponseCertiTab> =
            GroupRetrofitServiceImpl.service_ct_tab.requestList(
                userName = "김지현",
                date = serverDate //처음 date에 오늘 날짜
            )
        Log.d("changeServerDate", serverDate)
        call.enqueue(object : Callback<ResponseCertiTab> {
            override fun onFailure(call: Call<ResponseCertiTab>, t: Throwable) {
                // 통신 실패 로직
            }

            @SuppressLint("SetTextI18n")
            override fun onResponse(
                call: Call<ResponseCertiTab>,
                response: Response<ResponseCertiTab>
            ) {
                response.takeIf { it.isSuccessful }
                    ?.body()
                    ?.let { it ->
                        // do something
                        data = response.body()

                        Log.d("CertifTabFragment", data.toString())

                        //인증한 adapter에 Member 데이터 넣기
                        setCertifAdapter(it.data)

                    } ?: showError(response.errorBody())
            }
        })

    }
     private fun showError(error: ResponseBody?) {
        val e = error ?: return
        val ob = JSONObject(e.string())
        Toast.makeText(context, ob.getString("message"), Toast.LENGTH_SHORT).show()
    }

    private fun setCertifAdapter(certiList: List<ResponseCertiTab.Data>) {
        val mAdapter = CertifDateAdapter(certiList, context)
        certifRecycler.adapter = mAdapter
        mAdapter.notifyDataSetChanged()
        certifRecycler.setHasFixedSize(true)
    }

loadData 메소드를 만들어 서버와 통신을 요청하며, 카드뷰가 들어 있는 CertifDateAdapter에 서버와 통신하여 얻은 data를 adapter에 넣어줍니다.

👉 카드뷰가 들어 있는 CertifDateAdapter에서 데이터들을 연동

class CertifDateAdapter(
    private val certifList: List<ResponseCertiTab.Data>?,
    val context: Context?
) :
    RecyclerView.Adapter<CertifDateAdapter.ViewHolder>() {
    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { //
        var personName: TextView = itemView.findViewById(R.id.personName)
        var certifImg: ImageView = itemView.findViewById(R.id.certifImg)
        var userImg: ImageView = itemView.findViewById(R.id.my_iv_profile)
    }

    // 아이템 하나가 들어갈 뷰를 만들고 뷰 홀더에 넣어줌
    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): CertifDateAdapter.ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_certif_tab, parent, false)
        return ViewHolder(view)
    }

    //뷰를 그리는 부분
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item: ResponseCertiTab.Data = certifList!!.get(position)
        val imgUrl: String = certifList[position].image
        val userImgUrl: String = certifList[position].user_img

        if (imgUrl.length > 0) {
            Glide.with(holder.certifImg.context)
                .load(imgUrl)
                .error(android.R.drawable.stat_notify_error)
                .into(holder.certifImg)

        } else {
            Glide.with(holder.certifImg.context)
                .load(R.drawable.certif_un)
                .error(android.R.drawable.stat_notify_error)
                .into(holder.certifImg)
        }
        holder.personName.setText(certifList?.get(position)?.user_name)

        if (userImgUrl.length > 0) {
            Glide.with(holder.userImg.context)
                .load(userImgUrl)
                .error(android.R.drawable.stat_notify_error)
                .into(holder.userImg)

        } else {
            Glide.with(holder.userImg.context)
                .load(R.drawable.gr_img_profile_basic)
                .error(android.R.drawable.stat_notify_error)
                .into(holder.userImg)
        }
    }

    //리스트의 전체 개수
    override fun getItemCount(): Int {
        var size: Int = 0
        if (certifList != null) {
            size = certifList.size
        }
        return size
    }
}

카드뷰와 연결된 Adapter의 뷰를 그려주는 메소드인 onBindViewHolder 안에 서버에서 받아온 데이터와 연결해줍니다. img의 경우에는 url을 String으로 받아와 Glide 라이브러리를 사용하여 연결해줍니다.
(cf Glide 라이브러리 추가는 build.gradle 파일에서 해주셔야 합니다.)

profile
백엔드 개발자

0개의 댓글