본문 바로가기
Android App/Kotlin

네트워크-데이터통신/Github API 사용(*레트로핏(Retrofit) 및 converter-gson, Glide 라이브러리)

by AppJinny 2022. 12. 7.

*네트워크-데이터통신/Github API 사용(*레트로핏(Retrofit) 및 converter-gson, Glide 라이브러리)

*레트로핏(Retrofit)라이브러리

-데이터통신 라이브러리

-레트로핏 사용을 위해서는 인터페이스 정의 필수

-레트로핏 인터페이스는 호출방식, 주소, 데이터 등을 지정함

-레트로핏 라이브러리는 인터페이스를 해석해 HTTP통신을 처리하고 데이터를 가져옴

 

*converter-gson 라이브러리

-레트로핏에서 JSON 데이터를 사용하기 위해 사용하는 부가적인 라이브러리

 

*Glide 라이브러리

-가져올 데이터 중 이미지 데이터 주소가 포함되어 있을 때 HttpURLConnection을 직접 구현하여 이미지를 화면에 보여줄 수 있음

-HttpURLConnection직접 구현 시 효율성이 떨어짐

-대신 이미지를 화면에 보여주는 기능을 가진 로딩 라이브러리 사용

-로딩 라이브러리 : URL주소만 알려주면 해당 이미지가 있는 서버에 접속해 이미지를 다운로드하여 이미지뷰에 보내는 도구

-로딩 라이브러리 종류 중 Glide와 피카소를 많이 사용함

-Glide 홈페이지 : https://github.com/bumptech/glide

 

 

 

*깃허브 사용자 정보를 가져오는 앱 구현(Github API사용)

-Retrofit, converter-gson, Glide 라이브러리 사용

-JSON To Kotlin Class 플러그인을 사용하여 JSON형식의 텍스트 데이터를 코틀린 클래스로 변환

-적용할 JSON형식의 데이터(Github API) : https://api.github.com/users/Kotlin/repos

 

-build.gradle

-- android{} 에 뷰바인딩 추가

--dependencies{} 에 라이브러리 추가

//뷰바인딩
buildFeatures{
    viewBinding true
}
//레트로핏, converter-gson, glide 라이브러리 추가
//화면 상단 Open클릭 - Dependencies - + - library
//retrofit2:retrofit
//retrofit2:converter-gson
//bumptech.glide:glide 추가

dependencies {

    implementation 'com.github.bumptech.glide:glide:4.14.2'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

 

-AndroidManifest.xml

--인터넷 권한 추가

<!--  인터넷 권한 추가  -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <application

        android:usesCleartextTraffic="true"

 

-MainActivity.kt


/**깃허브 사용자 정보를 가져오는 앱 개발**/

//1
//레트로핏, converter-gson, glide 라이브러리 추가
//build.gradle(:app)

//2
//인터넷 접근을위한 권한 추가
//AndroidManifest.xml

//3
//안드로이드는 JSON형식으로 된 텍스트 데이터를 코틀린 클래스로
//간단하게 변환해주는 플러그인 JSON To Kotlin Class 을 지원함
//상단 메뉴 Android Studio - Preference - Plugins
//JSON To Kotlin Class 검색 후 설치

//4
//기본패키지 우클릭 - New - Kotlin data class File from JSON
//웹 브라우저에서 가져올 JSON형식 텍스트 데이터 복사 붙여넣기
//https://api.github.com/users/Kotlin/repos
//클래스명 Repository 설정 - Generate

//변환된 데이터 클래스 자동생성 됨
//(License, Owner, Repository, RepositoryItem)

//License, Owner: JOSN데이터가 JSON오브젝트를 값으로 사용하는 경우
//해당 데이터 이름으로 클래스 생성하여 사용

//Repository, RepositoryItem: Repository클래스는
//RepositoryItem의 배열을 상속받는 형태로 생성됨
//실제 데이터 구조는 RepositoryItem클래스에 생성됨

//5
//데이터를 출력할 화면 만들기
//activity_main.xml, recyclerView사용

class MainActivity : AppCompatActivity() {

    //뷰바인딩
    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        //7
        //데이터 요청을위해
        //커스텀 어댑터를 생성하여 어댑터변수 생성
        //레이아웃 리사이클러뷰 어댑터에 커스텀 어댑터 연결
        val adapter = CustomAdapter()
        binding.recyclerView.adapter = adapter

        //7-1
        //리사이클러뷰 리니어 레이아웃 매니저 연결
        binding.recyclerView.layoutManager = LinearLayoutManager(this)

        //8
        //Retrofit.Builder()를 사용해 레트로핏 생성하여
        //baseUrl이 되는 깃허브 도메인 주소와 JSON데이터를
        //Repository클래스의 컬렉션으로 변환해주는 컨버터 입력 후
        //build()메서드 호출하여 생성하여 변수에 담아 변수 생성
        val retrofit = Retrofit.Builder()
            .baseUrl("https://api.github.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        //9
        //버튼을 클릭하면 레트로핏을 이용해 데이터를 불러오고 어댑터에 세팅할 코드 작성
        //요청버튼을 클릭리스너 연결
        binding.btnRequest.setOnClickListener {

            //10
            //레트로핏 create() 메서드에
            //인터페이스를 파라미터로 넘겨주면
            //실행 가능한 서비스 객체를 생성해 반환해줌
            val githubService = retrofit.create(GithubService::class.java)
            //11
            //githubService는 GithubService인터페이스를 이용해 객체를 생성했기에
            //실행가능한 상태의 users()메서드를 가지고 있음
            //레트로핏 create() 메서드는 인터페이스를 실행가능한 객체로 만들면서
            //users()메서드 안에 비동기 통신으로 데이터를 가져오는
            //enqueue()메서드를 추가해 놓음...
            //enqueue()메서드가 호출되면 통신이 시작됨

            //enqueue()메서드 호출 후 깃허브API 서버로부터 응답을 받으면
            //enqueue()안에 작성하는 콜백 인터페이스가 작동하게 됨
            //enqueue()파라미터로 콜백 인터페이스를 구현해야함
            //콜백 인터페이스 구현 후 필수 메서드 2가지 구현...
            githubService.users().enqueue(object: Callback<Repository>{

                override fun onResponse(
                    call: retrofit2.Call<Repository>,
                    response: Response<Repository>
                ) {
                    //11-1
                    //통신이 성공적이면 onResponse메서드 호출
                    //두 번째 파라미터인 response의 body()메서드 호출 시
                    //서버로부터 전송된 데이터를 꺼낼 수 있음
                    //꺼낸 데이터를 Repository로 형변환 후 어댑터의 userList에 담음
                    adapter.userList = response.body() as Repository
                    //11-2
                    //어댑터로 리사이클러뷰에 변경된 사항 반영
                    adapter.notifyDataSetChanged()
                }

                override fun onFailure(call: retrofit2.Call<Repository>, t: Throwable) {
                }

            })

        }//btnRequest

    }//onCreate

}//MainActivity

//6**********
//레트로핏을 사용해 데이터를 조회하여 가져오고
//어댑터를 통해 목록에 출력하는 코드 작성

//레트로핏 사용을 위해서는 인터페이스 정의 필수*****
//레트로핏 인터페이스는 호출방식, 주소, 데이터 등 지정
//레트로핏 라이브러리는 인터페이스를 해석해 HTTP통신을 처리함
interface GithubService{

    //6-1
    //Github Api를 호출할 users메서드 생성
    //반환값은 Call<데이터클래스>형태로 작성
    //Call클래스 사용 시 retrofit2패키지 선택
    //레트로핏은 인터페이스에 지정된 방식으로 서버와 통신하고 데이터를 가져옴

    //@GET 어노테이션을 사용해 요청 주소 설정
    //요청주소는 Github도메인 제외하고 작성
    @GET("users/Kotlin/repos")
    fun users(): retrofit2.Call<Repository>
}

 

-JSON To Kotlin Class 설치

--안드로이드는 JSON형식으로 된 텍스트 데이터를 코틀린 클래스로 간단하게 변환해주는 플러그인 JSON To Kotlin Class 지원

--상단 메뉴 Android Studio - Preference - Plugins - JSON To Kotlin Class 검색 후 설치 

 

-Repository클래스 생성

--기본패키지 우클릭 - New - Kotlin data class File from JSON

--웹 브라우저에서 가져올 JSON형식 텍스트 데이터 복사 붙여넣기(https://api.github.com/users/Kotlin/repos)

--클래스명 Repository 설정 - Generate

--변환된 데이터 클래스 자동생성 : License, Owner, Repository, RepositoryItem

 

-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"
    android:padding="16dp"
    tools:context=".MainActivity">

<!--  깃허브 데이터 API주소를 요청할 버튼, 리사이클러 뷰 생성  -->
    <Button
        android:id="@+id/btnRequest"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:backgroundTint="@color/black"
        android:text="github 사용자 가져오기"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

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

<!--  리사이클러뷰 안에 넣을 아이템을 위한 레이아웃 생성 item_recycler.xml -->

</androidx.constraintlayout.widget.ConstraintLayout>

 

- item_recycler.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="100dp"
    android:padding="16dp">

<!--  이미지뷰1개와 텍스트뷰2개 생성  -->
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="100dp"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:text="이름"
        android:textSize="24dp"
        android:textStyle="bold"
        app:layout_constraintBottom_toTopOf="@+id/textId"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textId"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:text="아이디"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toBottomOf="@+id/textName" />

<!--  사용자 정보를 목록으로 보여주기 위해 리사이클러뷰 어댑터 생성  -->
<!--  패키지 우클릭 - CustomAdapter클래스 생성  -->

</androidx.constraintlayout.widget.ConstraintLayout>

 

- CustomAdapter.kt



//2
//RecyclerView의 Adapter상속받고 제네릭으로 Holder지정 후
//3개 필수 메서드 자동 생성
class CustomAdapter: RecyclerView.Adapter<CustomAdapter.Holder>() {

    //3
    //어댑터에서 사용할 데이터 컬렉션 변수 생성
    //사용할 데이터는 Repository클래스(아이템을 가지고 있는 배열...)사용
    //nullable로 선언
    var userList: Repository? = null

    //5
    //홀더를 생성하는 onCreateViewHolder
    //레이아웃을 인플레이트한 후 바인딩에 담아 홀더에 반환
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val binding = ItemRecyclerBinding.inflate(LayoutInflater.from(parent.context),parent,false)

        return Holder(binding)
    }

    //6
    //실제 목록에 뿌려지는 아이템을 그려주는 onBindViewHolder
    //현재 위치의 사용자 데이터를 userList에 가져와
    //아직 만들어지지 않은 홀더의 setUsers()메서드에 넘김
    override fun onBindViewHolder(holder: Holder, position: Int) {
        val user = userList?.get(position)
        holder.setUsers(user)
    }

    //4
    //목록에 출력되는 총 아이템 개수 구현
    override fun getItemCount(): Int {
        return userList?.size?: 0
    }

    //1
    //이너 클래스로 Holder클래스 생성
    //홀더의 생성자에서 바인딩을 전달받고
    //상속받은 ViewHolder에 binding.root전달
    inner class Holder(val binding: ItemRecyclerBinding): RecyclerView.ViewHolder(binding.root){
        //7
        //setUser()메서드 구현
        //1개의 RepositoryItem을 파라미터로 사용
        //userList가 nullable이기 때문에
        //userList의 현재위치를 담고있는 user변수도 nullable임
        fun setUsers(user: RepositoryItem?){
            //8
            //홀더가 가지고 있는 아이템 레이아웃에
            //데이터 하나씩 세팅
            //사용하는 데이터: 아바타주소, 사용자이름, 사용자아이디
            //RepositoryItem에는 각 데이터 이름을 사용함
            //아바타주소: user.owner.avatar_url
            //사용자이름: user.name
            //사용자아이디: user.node_id
            user?.let {
                //8-1
                //사용자 이름과 아이디 세팅
                binding.textName.text = user.name
                binding.textId.text = user.node_id
                //8-2
                //Glide.with를 사용하여 이미지 주소를 이미지뷰 안에 로드
                Glide.with(binding.imageView).load(user.owner.avatar_url).into(binding.imageView)
            }
        }//setUsers

    }//Holder

    //9
    //레트로핏을 사용해 데이터를 조회하여 가져오고
    //어댑터를 통해 목록에 출력하는 코드 작성
    //MainActivity.kt작성

}//CustomAdapter

 

 

-결과

 

 

 

 


이 포스팅에 작성한 내용은 고돈호, ⌜이것이 안드로이드다⌟, 한빛미디어(주), 2022 에서 발췌하였습니다.