Android 네트워크 : HTTP 통신 (Volley)

timothy jeong·2021년 11월 21일
0

Android with Kotlin

목록 보기
51/69

앱에서 네트워크 통신을 구현하려면 퍼미션을 설정해야한다.

<uses-permission android:name="android.permission.INTERNET"/>

안드로이드 앱은 네트워크 통신을 할때 기본으로 HTTPS 보안 프로토콜을 사용한다. 만약 일반 HTTPS 프로토콜로 통신하려면 특정 도메인만 허용하도록 선언해 줘야 한다. res/xml 폴더에 임의의 이름으로 XML 파일을 만들고 아래 처럼 작성한다.

<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true" >{HTTP 프로토콜로 접속을 허용하는 IP나 도메인}</domain>
    </domain-config>
</network-security-config>

이렇게 작성한 xml 파일을 메니페스트의 application 태그에 networkSecurityConfig 속성으로 알려주면 해당 도메인에 한해서만 HTTP 통신을 할 수 있다. 또는 메니페스트에 usesCleartextTraffic 속성을 true 로 설정하면 앱 전체에 모든 도메인의 서버와 HTTP 통신을 할 수 있다.

Volley 라이브러리

안드로이드 앱을 개발할 때 네트워크 프로그래밍을 돕는 라이브러리이며 구글에서 제공한다. 2013년 구글 IO 행사에서 공개된 라이브러리로, 안드로이드 앱에서 HTTP 통신을 좀 더 쉽게 구현하게 해준다.

dependencies {

    implementation 'com.android.volley:volley:1.1.1'
}

Vollery 클래스의 핵심 클래스는 RequestQueue 와 XXXRequest 이다.

  • RequestQueue : 서버 요청자
  • XXXRequest: XXX 타입의 결과를 받는 요청 정보

RequestQueue 객체는 서버에 요청을 보내는 역할을 하며 이때 서버 URL과 결과를 가져오는 콜백 등 다양한 정보는 XXXRequest 객체에 담아서 전송한다. 서버로부터 가져온 결과가 문자열이면 StringRequest 를 이용하는 것 처럼 데이터 타입에 따라 ImageRequest, JsonObjectRequest, JsonArrayRequest 등을 이용한다.

문자열 데이터 요청하기

StringRequest 는 서버에 문자열 데이터를 요청할 때 사용한다.

StringRequest(int method, String url, Response.Listener<String>, Response.ErrorListener errorListener)

StringRequest 생성자에는 HTTP 메서드, 서버 URL 그리고 서버로부터 결과를 받을 때 호출할 콜백과 서버 연동에 실패할 때 호출할 콜백을 지정한다.

        val url = "http://localhost:8008/"
        val stringRequest = StringRequest(
            Request.Method.GET,
            url,
            Response.Listener {
                Log.d("RESPONSE", "$it")
            },
            Response.ErrorListener { error ->
                Log.d("RESPONSE ERROR ", "$error")
            }
        )

StringRequest 객체 첫번째는 HTTP 메서드를 지정하고, 두번째는 요청을 보낼 url, 세번째 네번째는 각각 요청을 받았을때, 에러가 발생했을때의 콜백을 등록한다.

StringReuqest 에 담은 정보대로 서버에 요청을 보낼 때는 RequestQueue 객체를 이용한다.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val url = "http://localhost:8008/"
        val stringRequest = StringRequest(
            Request.Method.GET, url,
            { Log.d("RESPONSE", "$it") },
            { error -> Log.d("RESPONSE ERROR ", "$error") })
        
        val queue = Volley.newRequestQueue(this)
        queue.add(stringRequest) // 서버로 요청을 보냄.
    }
}

만약 서버로 추가적인 데이터를 보내고 싶다면, GET 방식에서는 url 뒤에 추가적인 파라미터를 더 붙이면 되지만, Post 방식에서는 StringRequest를 상속받은 클래스를 이용해야 한다.

val stringRequest = object : StringRequest(
            Request.Method.POST, url,
            { Log.d("RESPONSE", "$it") },
            { error -> Log.d("RESPONSE ERROR ", "$error") }) {
            override fun getParams(): MutableMap<String, String> {
                return mutableMapOf<String, String>("one" to "Hello", "two" to "World")
            }
        }

이미지 데이터 요청하기

서버에 이미지를 요청할 때는 ImageRequest를 이용한다.

public ImageRequest(String url, Response.Listener<Bitmap> listener, int MaxWidth, int MaxHeight, ScaleType scaleType, Config decodeConfig, @Nullable Reponse.ErrorListener errorListener)

이름만으로 예측 가능한 파라미터를 제외하고 나머지를 설명하자면,

  • maxWidth, maxHeight : 지정한 값으로 이미지 크기 조절해서 전달, 만약 0으로 설정하면 크기 조절 업이 서버가 전달하는 이미지를 그대로 받음
  • decodeConfig : 이미지 형식 지정
        val imageRequest = ImageRequest(
            url,
            Response.Listener<Bitmap> { response -> binding.imageView.setImageBitmap(response) },
            0,
            0,
            ImageView.ScaleType.CENTER_CROP,
            null,
            Response.ErrorListener { error ->  Log.d("RESPONSE ERROR ", "$error") }
        )
        val queue = Volley.newRequestQueue(this)
        queue.add(imageRequest)

화면 출력용 이미지 데이터 요청하기

만약 서버에서 가져온 이미지를 화면에 출력만 한다면 ImageRequest를 사용할 수도 있지만, NetworkImageView 를 사용하면 조금 더 편리하다. NetworkImageView 는 Volley 라이브러리에서 제공하는 이미지 출력용 뷰이다.

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/networkImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

이 객체의 setImageUrl() 함수만 호출하면 서버에서 이미지를 가져오는 통신부터 이미지를 NetworkImageView 에 출력하는 것까지 자동으로 이루어진다.

setImageUrl(String url, ImageLoader imageLoader)

setImageUrl() 함수만으로도 서버에 요청을 보낼 수 있다. 즉, RequestQueue의 add() 함수를 호출하지 않아도 서버와 자동으로 연동된다. 대신 이 함수의 두번째 매개변수에 ImageLoader 를 상속받은 하위 클래스의 객체를 지정해야 한다.

val queue = Volley.newRequestQueue(this)
        val imgMap = HashMap<String, Bitmap>()
        val imageLoader = ImageLoader(queue, object : ImageLoader.ImageCache{
            override fun getBitmap(url: String): Bitmap? {
                return imgMap[url]
            }

            override fun putBitmap(url: String, bitmap: Bitmap) {
                imgMap[url] = bitmap
            }
        })
        binding.networkImageView.setImageUrl(url, imageLoader)

ImageLoader 객체를 setImageUrl() 함수의 두 번째 매개변수에 지정하면 서버 이미지를 가져오기 전에 ImageLoader 의 getBitmap() 함수가 자동으로 호출된다.
이 함수의 반환값이 널이면 서버에 요청을 보내고 Bitmap 객체이면 요청을 보내지 않고 Bitmap 객체를 그대로 NetworkImageView에 출력한다.
getBitmap() 함수가 null 을 반환하여 서버로부터 이미지를 가져오면 putBitmap() 함수가 자동으로 호출되어 서버 이미지를 putBitmap() 두번째 매개변수로 전달해준다. 결국 같은 URL의 이미지를 반복해서 가져오지 않도록 한다.

JSON 데이터 요청하기

서버에 JSON 데이터를 요청할 때는 JsonObejctRequest 를 이용한다. 그러면 자동으로 JSON 데이터를 파싱한 JSONObject 객체가 콜백 함수에 전달된다.

jsonObejctRequest(int method, String url, @Nullable JSONObject jsonReqeust, Response.Listener<JSONObject> listenenr, Reponse.ErrorListener errorListener)

서버에 데이터를 전송해야 한다면 JsonObjectRequest() 함수의 세번째 매개변수에 JSONObject로 지정할 수 있으며, null 이면 서버에 전송할 데이터가 없다는 의미이다.

        val jsonRequest = JsonObjectRequest(
            Request.Method.GET,
            url,
            null,
            Response.Listener<JSONObject> { response ->  
                val title = response.getString("title")
                val date = response.getString("date")
            },
            Response.ErrorListener { //error
                }
        )
       val queue = Volley.newRequestQueue(this)
       queue.add(jsonRequest)

JSON 배열 요청하기

서버에 JSON 배열을 요청할 때는 JsonArrayRequest 를 이용한다.

    public JsonArrayRequest(
            String url, Listener<JSONArray> listener, @Nullable ErrorListener errorListener) {
        super(Method.GET, url, null, listener, errorListener);
    }
val jsonRequest = JsonArrayRequest(
            Request.Method.GET,
            url,
            null,
            Response.Listener<JSONArray> { response -> 
                for (i in 0 until response.length()) {
                    val jsonObject = response[i] as JSONObject
                    val title = jsonObject.getString("title")
                    val date = jsonObject.getString("date")
                }
            },
            Response.ErrorListener { // error
                }
        )

        val queue = Volley.newRequestQueue(this)
        queue.add(jsonRequest)
profile
개발자

0개의 댓글