『Do it! 깡샘의 안드로이드 앱 프로그래밍 with 코틀린』 교재를 바탕으로 정리한 내용입니다.
<uses-permission android:name="android.permission.INTERNET" />
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">xxx.xxx.xxx.xxx</domain>
</domain-config>
</network-security-config>
<application
(... 생략 ...)
android:networkSecurityConfig="@xml/network_security_config">
<application
(... 생략 ...)
android:usesCleartextTraffic="true">
implementation 'com.android.volley:volley:1.2.1'
// 문자열 요청 정의
val stringRequest = StringRequest(
Request.Method.GET,
url,
Response.Listener<String> {
Log.d("kkang", "server data : $it")
},
Response.ErrorListener { error ->
Log.d("kkang", "error......$error")
})
// 서버에 요청
val queue = Volley.newRequestQueue(this)
queue.add(stringRequest)
// POST 방식으로 데이터 전송
val stringRequest = object : StringRequest(
Request.Method.POST,
url,
Response.Listener<String> {
Log.d("kkang", "server data : $it")
},
Response.ErrorListener { error ->
Log.d("kkang", "error......$error")
}) {
override fun getParams(): MutableMap<String, String> {
return mutableMapOf<String, String>("one" to "hello", "two" to "world")
// MutableMap 객체에 전달할 데이터 담아서 반환하면 서버에 요청할 때 알아서 함께 전송해 줌
}
}
val imageRequest = ImageRequest(
url,
Response.Listener { response -> binding.imageView.setImageBitmap(response) },
0,
0,
ImageView.ScaleType.CENTER_CROP,
null,
Response.ErrorListener { error ->
Log.d("kkang", "error......$error")
})
val queue = Volley.newRequestQueue(this)
queue.add(imageRequest)
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/networkImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
val queue = Volley.newRequestQueue(this)
// queue.add(imageRequest)
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)
val jsonRequest = JsonObjectRequest(
Request.Method.GET,
url,
null,
Response.Listener<JSONObject> { response -> //JSON을 파싱한 JSONObject 객체 전달
val title = response.getString("title")
val date = response.getString("date")
Log.d("kkang", "$title, $date")
},
Response.ErrorListener { error -> Log.d("kkang", "error......$error") }
)
val queue = Volley.newRequestQueue(this)
queue.add(jsonRequest)
val jsonArrayRequest = 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")
Log.d("kkang", "$title, $date")
}
},
Response.ErrorListener { error -> Log.d("kkang", "error......$error") }
)
val queue = Volley.newRequestQueue(this)
queue.add(jsonArrayRequest)
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
{
"id" : 7,
"email" : "michael.lawson@reqres.in",
"first_name" : "Michael",
"last_name" : "Lawson",
"avatar" : "https://reqres.in/img/faces/7-image.jpg"
}
→ 위의 JSON정보를 담는 모델 클래스
data class UserModel(
var id: String,
@SerializedName("first_name") // 키와 프로퍼티 이름이 다른 경우 어노테이션 사용
var firstName: String,
// @SerializedName("last_name") // last_name -> lastName 자동으로 저장
var lastName: String,
var avatar: String,
var avatarBitmap: Bitmap
)
{
"page" : 2,
"per_page" :6,
"total" : 12,
"total_pages" : 2,
"data" : [
{
"id" : 7,
"email" : "michael.lawson@reqres.in",
"first_name" : "Michael",
"last_name" : "Lawson",
"avatar" : "https://reqres.in/img/faces/7-image.jpg"
},
{
"id" : 7,
"email" : "michael.lawson@reqres.in",
"first_name" : "Michael",
"last_name" : "Lawson",
"avatar" : "https://reqres.in/img/faces/7-image.jpg"
}
],
}
→ 위의 JSON정보를 담는 모델 클래스
data class UserListModel(
var page: String,
@SerializedName("per_page")
var perPage: String,
var total: String,
@SerializedName("total_pages")
var totalPages: String,
var data: List<UserModel>?
)
interface INetworkService {
// @GET : 서버 연동 시 GET 방식으로 하겠다는 의미
// @Query : 서버에 전달되는 데이터
// @Url : 요청 URL
@GET("api/users")
fun doGetUSerList(@Query("page") page: String): Call<UserListModel>
@GET
fun getAvatarImage(@Url url: String): Call<ResponseBody>
}
val retrofit: Retrofit
get() = Retrofit.Builder()
.baseUrl("https://reqres.in/")
.addConverterFactory(GsonConverterFactory.create()) //GsonConverter 이용하겠다는 의미
.build()
val networkService: INetworkService = retrofit.create(INetworkService::class.java)
val userListModel = networkService.doGetUSerList("1")
userListCall.enqueue(object : Callback<UserListModel> {
override fun onResponse(call: Call<UserListModel>, response: Response<UserListModel>) {
val userList = response.body()
(... 생략 ...)
}
override fun onFailure(call: Call<UserListModel>, t: Throwable) {
call.cancel()
}
})
Retrofit은 개발자가 작성한 서비스 인터페이스에 따라 통신을 수행하기 때문에 어떤 애너테이션을 작성하는 지가 핵심 !
@GET, @POST, @PUT, @DELETE, @HEAD
// 인터페이스에 선언한 함수
@GET("users/list?sort=desc")
fun test1(): Call<UserModel>
// Call 객체를 얻는 구문
val call: Call<UserModel> = networkService.test1()
//최종 서버 요청 URL
https://reqres.in/users/list?sort=desc
// 인터페이스에 선언한 함수
@GET("group/{id}/users/{name}")
fun test2(
@Path("id") userId: String,
@Path("name") arg2: String,
): Call<UserModel>
// Call 객체를 얻는 구문
val call: Call<UserModel> = networkService.test2("10", "kkang")
//최종 서버 요청 URL
https://reqres.in/group/10/users/kkang
// 인터페이스에 선언한 함수
@GET("group/users")
fun test3(
@Query("sort") arg1: String,
@Query("name") arg2: String,
): Call<UserModel>
// Call 객체를 얻는 구문
val call: Call<UserModel> = networkService.test3("age", "kkang")
//최종 서버 요청 URL
https://reqres.in/group/users?sort=age&name=kkang
// 인터페이스에 선언한 함수
@GET("group/users")
fun test4(
@QueryMap options: Map<String, String>,
@Query("name") name: String,
): Call<UserModel>
// Call 객체를 얻는 구문
val call: Call<UserModel> = networkService.test4(
mapOf<String, String>("one" to "hello", "two" to "world"), "kkang")
//최종 서버 요청 URL
https://reqres.in/group/users?one=hello&two=world&name=kkang
// 인터페이스에 선언한 함수
@GET("group/users")
fun test5(
@Body user: UserModel,
@Query("name") name: String,
): Call<UserModel>
// Call 객체를 얻는 구문
val call: Call<UserModel> = networkService.test5(
UserModel(id="1", firstName = "gildong", lastName = "hong", avatar = "someurl"),
"kkang"
)
//최종 서버 요청 URL
https://reqres.in/group/users?name=kkang
//서버에 스트림으로 전송되는 데이터
{"id":"1", "first_name":"gildong", "last_name":"hong", "avatar":"someurl"}
// 인터페이스에 선언한 함수
@FormUrlEncoded
@POST("users/edit")
fun test6(
@Field("first_name") first: String?,
@Field("last_name") last: String?,
@Query("name") name: String?,
): Call<UserModel>
// Call 객체를 얻는 구문
val call: Call<UserModel> = networkService.test6(
"gildong 길동",
"hong 홍",
"kkang"
)
//최종 서버 요청 URL
https://reqres.in/users/edit?name=kkang
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
fun test8(): Call<UserModel>
// 인터페이스에 선언한 함수
@GET
fun test9(@Url url: String, @Query("name") name: String): Call<UserModel>
// Call 객체를 얻는 구문
val call = networkService.test9("http://www.google.com", "kkang")
//최종 서버 요청 URL
http://www.google.com/?name=kkang