티스토리 뷰

Android App Coding

안드로이드 네트워크 2편 Network

IT Knowledge Share 2021. 7. 18. 03:43
반응형

이전에는 HttpUrlConnection을 통해 네트워크 작업이 이루어지는 코딩을 했었습니다.

서버와 통신하는 코드를 작성하는 부분이 복잡하고, 관리 포인트가 많았습니다.

 

이번에는 라이브러리를 이용해 서버와 통신하는 방법을 알아봅니다.

안드로이드에서 네트워크 라이브러리로 자주 사용되는 것은 Volley, Retrofit 등이 있습니다.

Retrofit 라이브러리를 이용해서 서버와 통신할 수 있도록 알아봅니다.

 

우선 build.gradle의 앱 단위 dependencies 부분에서 Retrofit 라이브러리를 implementation 합니다. 그리고 Buffer를 읽고 난후 Gson 라이브러리를 통해서 서버로 부터 받은 응답을 원하는 데이터 타입으로 바꿔주는 역할을 자동으로 해주는 라이브러리도 추가합니다. converter-gson 처럼 말이죠.

dependencies {
 implementation 'com.squareup.retrofit2:retrofit:2.3.0'
 implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
}
반응형

액티비티 파일을 생성하고, RetrofitActivity 클래스에서 라이브러리를 이용할 수 있도록 작업합니다.

baseURL 부분은 변하지 않는 기본적인 URL 주소를 적습니다. addConvertFactory는 Buffer로 읽은 데이터를 Gson 라이브러리로 받아서 원하는 데이터로 바꿔주는 역할을 합니다.

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_retrofit)

        val retrofit = Retrofit.Builder()
            .baseUrl("URL 주소")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
}

그리고 URL주소의 변하는 부분을 관리해줄 수 있도록 서비스 액티비티를 만드는데, 인터페이스를 받도록 합니다.

해당 서비스 파일에서는 어노테이션(@)을 사용하고 뒤에 Request 메소드(GET, POST, PUT, DELETE)를 적어줍니다.

메소드 안에는 baseURL의 바뀌는 뒷 부분만 적어줍니다. 어노테이션 안의 함수 타입은 최종적으로 받게 되는 타입을 적습니다. 그리고 Call<>처럼, 제너릭 타입 안에 최종 타입을 넣어줍니다.

 

@GET("json/users/") 부분을 보면, 해당 주소에 GET 요청을 하는데, 주소를 통해서 얻은 데이터는 응답 부분에서 Array<User> 타입으로 사용한다는 의미입니다.

package com.example.myapplication

import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.*


interface RetrofitService {

    @GET("json/users/")
    fun getUsersList(): Call<ArrayList<User>>


}

다시 onCreate 부분에서 RetrofitService를 연결시켜 줍니다. 이렇게 생성된 service를 통해서 데이터 통신이 가능해지게 됩니다.

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_retrofit)

        val retrofit = Retrofit.Builder()
            .baseUrl("URL 주소")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            
        val service = retrofit.create(RetrofitService::class.java)
}

이제 실제로 service를 사용합니다. service를 통해서 어노테이션 안에서 만든 함수를 가져올 수 있습니다. enqueue 메소드는 데이터를 대기 상태로 만드는 메소드입니다. 따라서 해당 통신이 대기 상태로 됩니다. onFailure, onResponse 메소드를 implement 합니다. 통신이 실패하면 onFailure, 통신이 성공하면 onResponse 메소드가 실행됩니다.

 

response가 isSuccessful 이라면, val userList = response.body() 처럼 우리가 원하는 데이터 타입으로 변형할 수 있도록 합니다. response.body()는 말그대로 데이터, response.erroBody()는 에러 내용, response.code()는 2xx, 3xx 등의 코드를 확인할 수 있습니다.

 

만약에 실패했다면, call.isCancelled 이나 call.isExecuted 처럼, 취소되었는지 실행되었는지 묻거나 call.cancel()로 실패한 요청을 취소할 수 있습니다.

service.getUserList().enqueue(object : Callback<ArrayList<User>> {
            override fun onFailure(call: Call<ArrayList<User>>, t: Throwable) {
              call.isCancelled
              call.isExecuted
              call.cancel()
       
            }

            override fun onResponse(
                call: Call<ArrayList<User>>,
                response: Response<ArrayList<User>>
            ) {
                if (response.isSuccessful) {
                    val userList = response.body()

                    val code = response.code()

                    val header = response.headers()
                    
                    val error = response.erroBody()
                }
            }
        })

RetrofitService에서 다른 요청 메소드를 어떻게 표현하는지 살펴봅니다.

@POST의 경우, @Body 부분에는 HashMap을 사용해서 포스트 방식의 키-밸류 값을 넘어갈 수 있도록 합니다. 키값은 문자열이고, 밸류 값은 Any 타입으로 지정합니다. HashMap 타입의 변수 이름은 params로 설정했습니다.

그리고 응답으로는 포스트 요청을 보낸 Users가 돌아오게 되며, Call< >의 제너릭 타입에 넣어줍니다.

interface RetrofitService {
    @POST("json/users/")
    fun createUsers(
        @Body params: HashMap<String, Any>
    ): Call<Users>

    @POST("json/users/")
    fun createUserss(
        @Body users: Users
    ): Call<Users>

    
}

포스트 요청의 경우, onCreate에서 사용법은 다음과 같습니다.

val params = HashMap<String, Any>()

        params.put("id", "벚꽃")
        params.put("pwd", 4567)

        service.createUsers(params).enqueue(object : Callback<User> {
            override fun onFailure(call: Call<PersonFromServer>, t: Throwable) {
            }

            override fun onResponse(
                  call: Call<User>,
                  response: Response<User>
            ) {
                if (response.isSuccessful) {
                    val user = response.body()
                }

            }
        })

서비스의 포스트 요청에서 HashMap 대신에 객체를 생성해서 데이터를 받을 수도 있습니다.

@POST("json/users/")
    fun createUserss(
        @Body users: Users
    ): Call<Users>

사용법은 아래와 같습니다. 아래와 같이, 바로 객체를 생성해주면 됩니다.

 val user = User(id = "하늘", pwd = 4567)
        service.createUserss(user).enqueue(object : Callback<User> {
            override fun onFailure(call: Call<User>, t: Throwable) {
            }

            override fun onResponse(
                call: Call<User>,
                response: Response<User>
            ) {
                if (response.isSuccessful) {
                    val person = response.body()
                }

            }
        })

그럼 안드로이드 네트워크에 대한 설명은 여기서 마치겠습니다.

반응형
댓글