앱에서 네트워크 통신을 구현하려면 퍼미션을 설정해야한다.
<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 통신을 할 수 있다.
안드로이드 앱을 개발할 때 네트워크 프로그래밍을 돕는 라이브러리이며 구글에서 제공한다. 2013년 구글 IO 행사에서 공개된 라이브러리로, 안드로이드 앱에서 HTTP 통신을 좀 더 쉽게 구현하게 해준다.
dependencies {
implementation 'com.android.volley:volley:1.1.1'
}
Vollery 클래스의 핵심 클래스는 RequestQueue 와 XXXRequest 이다.
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)
이름만으로 예측 가능한 파라미터를 제외하고 나머지를 설명하자면,
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 데이터를 요청할 때는 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 배열을 요청할 때는 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)