ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android][Kotlin] : Retrofit (MVVM 코루틴)
    안드로이드 2021. 7. 15. 18:50
    728x90
    반응형

    Retrofit


    Retrofit의 사전적 의미부터 알아보자면 "개조" 라는 의미로, 안드로이드에서의 Retrofit은 안드로이드 애플리케이션(클라이언트)과 서버간에 REST 통신을 위해 사용하기 쉽게 만들어놓은 라이브러리이다. 해당 라이브러리를 통해 JSON 구조의 데이터를 쉽게 가져오고 업로드할 수 있다.

     

    *REST 란? : 웹과 같은 분산 하이퍼 미디어 환경에서 표준화된 HTTP 메서드(GET,POST,PUT,DELETE)를 통해 자원의 존재/상태 정보를 주고 받는 웹 아키텍처.

     

    안드로이드 통신 라이브러리


    초기의 안드로이드 통신은 HttpClient를 사용했다. HttpClient에는 몇 가지 버그가 있어 HttpUrlConnection이 권장되고 나서 쭈욱 사용하다 복잡했던 사용법으로 인해 Volley라는 녀석이 나와 표준 라이브러리로 사용되었다.

    하지만 안드로이드 버전 5.1에서 HttpClient가 Deprecated된 후, HttpClient에 의존하던 Volley도 Deprecated 되었다. Square에서 만들어진 라이브러리인 OkHttp와 그 래퍼인 Retrofit은 하나의 선택처럼 되어버렸다. Retrofit에서는 통신 클라이언트 부분과 콜백 형식 등을 플러그로 변경하는 것이 가능해 매우 인기있는 통신 라이브러리가 되었다.

    Retrofit의 장점


    Retrofit이 인기있는 이유는 속도, 편의성, 가독성이 있다. 

    • 속도 : OkHttp 같은 경우 사용시 대개 Asyntask를 통해 비동기로 실행하게 되는데 성능상 느리다는 이슈가 있었다. Retorfit은 Asyntask를 사용하지 않고 자체적인 비동기 실행과 스레드 관리를 통해 속도를 훨씬 빠르게 끌어 올렸다.

    Retrofit, Volley, Asyntask 성능 비교

    사진 출처

     

    Android Async HTTP Clients: Volley vs Retrofit - Instructure Tech Blog

    We recently released a new version of our mobile app for Android. Although it was a huge improvement from previous installments in terms of features, design, and usability, there was one nagging issue in the back of our minds: speed. There are times when t

    instructure.github.io

    • 편의성 : OkHttp에서는 쿼리스트링, request, response 설정 등 반복적인 작업이 필요한데, Retrofit에서는 이러한 과정을 모두 라이브러리에 넘겨서 처리해, 함수 호출 시 파라미터만 넘기면 된다.
    • 가독성 : Interface 내에 annotation을 사용해 호출할 함수를 파라미터와 함께 정의해 가독성이 뛰어나다.

     

    코틀린에서 Retrofit을 사용하는 방법


    1. Retrofit.Builder를 선언한 클래스
    2. JSON 형태의 모델 클래스
    3. HTTP 작업을 정의하는 인터페이스

    1. 먼저 java 1.8을 사용하기 위한 종속성과 by viewModels를 사용해 편하게 viewModel을 ViewModelProvider를 사용하지 않고 간편하게 생성해주기 위한 종속성 추가. build.gradle(:app)

    android{
    	// java 1.8 사용하기 위한 종속성 추가
    	compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
        //by viewModels 사용하여 ViewModel 생성하기 위한 종속성 추가
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }

    2.  서버 통신을 위해 인터넷을 사용하기 위한 permission 추가 (manifests)

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

    3. 서버 통신을 위한 라이브러리도 추가!

    //레트로핏
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    
    //json형태의 객체를 gson으로 파싱해주는 Converter
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    
    //viewmodelScope lifecycle-viewmodel-ktx:2.2.0이상
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
    //liveData
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
    
    //viewmodels
    implementation 'androidx.activity:activity-ktx:1.2.3'
    implementation 'androidx.fragment:fragment-ktx:1.3.5'

    4. 서버에서 오는 JSON객체를 매핑해주기 위한 DataClass 생성

    data class UserInfo(
        /*해당 유저 id*/
        @SerializedName("login") @Expose val id:String,
        /*해당 유저 github 주소*/
        @SerializedName("url") @Expose val gitUrl: String,
        /*public 레파지토리 개수*/
        @SerializedName("public_repos") @Expose val publicRepos: Int,
        /*팔로워 수*/
        @SerializedName("followers") @Expose val followers:Int,
        /*팔로잉 수*/
        @SerializedName("following") @Expose val following: Int,
    )

    어노테이션 : 주석이라는 뜻으로 

    @SerializedName : JSON으로 serialzie 될때 이름을 명시하는 목적으로 사용되는 field 마킹 어노테이션이다.
    @Expose : object 중 해당 값이 null일 경우, json으로 만들 필드를 자동으로 생략해준다.

     

     

    5.  Retrofit Builder 생성

    object RetrofitClient {
        private var instance: Retrofit? = null
    
        fun getInstance() :ApiInterface? {
            if(instance ==null){
                val gson = GsonBuilder()
                    .setLenient()
                    .create()
                instance = Retrofit.Builder()
                    .baseUrl("https://api.github.com/")
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build()
            }
            return instance?.create(ApiInterface::class.java)
        }
    }

    RetrofitBuilder를 싱글톤 패턴으로 생성해 객체를 하나만 생성시켰다.

    baseUrl : 통신을 요청할 서버 주소

    addConverterFactory : json 형태의 데이터를 코틀린에서 사용하기위해 Gson으로 변환

     

    6. 서버에 어떤식으로 파라미터를 넘겨 요청을 보낼건지 동작을 정의해놓은 인터페이스

    interface ApiInterface {
    //  GitHub 유저 'jgh6272'의 정보를 요청하는 메소드
        @GET("/users/jgh6272")
        suspend fun userInfo() :UserInfo
    
    }

    suspend fun : 코루틴 내에서 함수가 호출되도록 강제하는 Kotlin의 방식

    @GET : CRUD의 READ. 서버 내 데이터 조회 용도, URL에 모두 표현

    @POST : CRUD의 CREATE. 서버에 데이터를 생성, BODY에 전송할 데이터를 담아서 요청하는 방식

    @PUT : CRUD의 UPDATE. @POST와 같이 BODY에 데이터를 담아 전송

    @DELETE : CRUD의 DELETE 방식

     

    7. viewModel

    class GitHubViewModel :ViewModel(){
        val service: ApiInterface? = RetrofitClient.getInstance()
        val userInfoLiveData = MutableLiveData<UserInfo>()
    
        fun userInfo(){
            viewModelScope.launch {
                var data = service?.userInfo()
                userInfoLiveData.value = data!!
            }
        }
    }

    viewModelScope : 비동기 코드를 작성할 수 있게 하며, viewmodel이 활성 상태인 경우에만 실행해야 할 작업이 있을때 사용한다.

    service?.userInfo()를 통해 요청한 응답을 data 변수에 담고 해당 data 변수를 LiveData에 담아 데이터 작업.

     

    8.  MainActivity

    class MainActivity : AppCompatActivity() {
    
        //by viewModels()를 사용하면 ViewModelProvider를 사용하지 않고 viewmodel을 지연 생성할 수 있다.
        private val viewModel:GitHubViewModel by viewModels()
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            viewModel.userInfo()
            viewModel.userInfoLiveData.observe(this, Observer {
                Log.d("git userInfo", "User: ${it.id}")
                Log.d("git userInfo", "Repository Count: : ${it.publicRepos}")
                Log.d("git userInfo", "Git Url: ${it.gitUrl}")
                Log.d("git userInfo", "Followers: ${it.followers}")
                Log.d("git userInfo", "Following: ${it.following}")
            })
        }
    }

    MainActivity에서 ViewModel을 생성하고, 요청 보내는 메소드 실행하고 LiveData를 통해 객체 관찰.

    반응형

     

    9. 실행 결과

    GitHub 통신 결과

    728x90
    반응형

    댓글

Designed by ZibroTistory.