-
[Android/Kotlin] 네트워크(Network)Android/Kotlin 2022. 7. 9. 19:53반응형
[모든 포스팅은 개인적 공부를 위해 작성된 글입니다]
<서버와 안드로이드 통신>
- 주로 JSON(JavaScript Object Notation) 사용
- INTERNET 권한 추가해 줘야 함
<uses-permission android:name="android.permission.INTERNET" />
<JSON 형식>
- [] -> List 의미- {} -> 객체 의미
ex) json response 예제
{ "squadName": "Super hero squad", "homeTown": "Metro City", "formed": 2016, "secretBase": "Super tower", "active": true, "members": [ { "name": "Molecule Man", "age": 29, "secretIdentity": "Dan Jukes", "powers": [ "Radiation resistance", "Turning tiny", "Radiation blast" ] }, { "name": "Madame Uppercut", "age": 39, "secretIdentity": "Jane Wilson", "powers": [ "Million tonne punch", "Damage resistance", "Superhuman reflexes" ] }, { "name": "Eternal Flame", "age": 1000000, "secretIdentity": "Unknown", "powers": [ "Immortality", "Heat Immunity", "Inferno", "Teleportation", "Interdimensional travel" ] } ] }
*json 객체 출처*
https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/JSON
JSON으로 작업하기 - Web 개발 학습하기 | MDN
JavaScript Object Notation (JSON)은 Javascript 객체 문법으로 구조화된 데이터를 표현하기 위한 문자 기반의 표준 포맷입니다. 웹 어플리케이션에서 데이터를 전송할 때 일반적으로 사용합니다(서버에서
developer.mozilla.org
<JSON Parsing>
- json 객체를 kotlin이나 Java가 알아들을 수 있게 변환(해석)하는 작업- Serializable(직렬화) 필요
- JSON 객체의 정보를 Kotlin이나 Java가 이해할 수 있는 틀(ex class)에 넣어주는 작업
<자주 사용되는 Request Type>
- 1. GET
- 지정한 URI의 정보(리소스) 요청
- 잘 처리된 경우 Status Code : 200 OK
- 2. POST
- 요청과 데이터 담아 전송 -> 정보 추가(해당 URI에 리소스 생성) 요청
- 잘 처리된 경우 Status Code : 201 Created
- 3. DELETE
- 지정한 URI의 정보 삭제 요청
- 4. PUT
- 지정한 URI의 정보 수정 요청
<Status Code>
- 100번대 : 요청 받아 작업 진행 중
- 200번대 : 작업 성공
- 300번대 : 요청 완료 위해 리다이렉션 해야 함
- 400번대 : 클라이언트 오류, 요청 올바르지 않음
- 500번대 : 서버 오류, 요청은 올바르지만 서버가 응답할 수 없음
<setRequestProperty()>
- setRequestProperty("Key", "Value")
Key Value 의미 Accept application/xml 응답 결과를 xml 형태로 받음으로 요청 Accept application/json 응답 결과를 json 형태로 받음으로 요청 Content-Type application/xml 요청 시 application/xml 형태로 전달 Content-Type application/json 요청 시 application/json 형태로 전달 Content-Type text/html 요청 시 text/html 형태로 전달 Cache-Control no-cache 캐시 설정 <가져온 데이터 담을 틀(Class) 만들기>
- Serializable 상속 받아야 함
class Person( var id: Int? = null,//서버에서 자동 생성 var name: String? = null, var age: Int? = null, var intro: String? = null ):Serializable
<요청한 데이터 가져와서 읽기>
- GSON 사용
- GSON : JSON 파싱, 생성 위해 사용되는 구글 오픈소스(Java Object를 JSON 문자열로 변환, JSON 문자열을 Java Object로 변환할 수 있음)
- gralde app 수준
implementation 'com.google.code.gson:gson:2.8.5'
class NetworkTask(): AsyncTask<Any?, Any?, Any?>(){ override fun doInBackground(vararg p0: Any?): Any? { val urlString: String = "주소" val url: URL = URL(urlString) val connection: HttpURLConnection = url.openConnection() as HttpURLConnection//요청 보냄 connection.requestMethod="GET"//GET 방식으로 요청(requestMethod == 요청 방식 설정) connection.setRequestProperty("Content-Type","application/json")//헤더 작성 var buffer = "" if(connection.responseCode == HttpURLConnection.HTTP_OK){ val reader = BufferedReader( InputStreamReader(connection.inputStream, "UTF-8") )//통신은 Byte 형태로 이루어 지는데 이를 사람이 읽을 수 있는 형태로 가져옴 buffer = reader.readLine() }//responseCode == StatusCode, HTTP_OK == 200 OK val data = Gson().fromJson(buffer, Array<Person>::class.java) /* * Array<> 붙이지 않은 경우 * - Gson이 기대하는 객체는 Array 형태인데 person::class.java로 하면 객체 형식으로 가져오겠다는 의미이므로 Array 붙여줘야 함 */ val age = data[0].age//가져온 데이터 출력 return null } }
- reader를 생성하는 부분(BufferReader, InputStreamReader 부분)은 거의 똑같이 사용됨
<서버 통신 지원하는 라이브러리>
- Volly
- Retrofit
<Retrofit 사용하기(비동기 방식)>
- gradle app 수준
implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
//도메인(baseURL) 뒷부분 URL(변하는 부분) 관리할 수 있는 서비스 생성(interface로 생성) interface RetrofitService { //GET 호출하여 서버로부터 데이터 얻기 위한 위한 함수 생성(GET 요청) @GET("baseURL 뒷부분")//baseURL 뒷부분 입력 fun getStudentsList(): Call<ArrayList<Person>>//GET안에 입력한 URL에 데이터를 요청하는데 그 response의 타입이 ArrayList<Person>이다라는 뜻 //서버 데이터 업데이트 하기 위한 함수 생성(POST 요청) @POST("baseURL 뒷부분") fun createStudent( @Body params: HashMap<String, Any> /* * HashMap<Key, Value> * 예제로 든 테이블의 Key 값은 모두 String 형태지만 Value 값은 String, Int 등 여러가지로 다양하기 때문에 모든 자료형 들어갈 수 있는 Any로 설정 */ ): Call<Person> @POST("baseURL 뒷부분") fun createStudentEasy( @Body person: Person ): Call<Person> }
val retrofit = Retrofit.Builder().baseUrl("도메인 주소").addConverterFactory(GsonConverterFactory.create()).build()//Retrofit 생성 //baseUrl -> 도메인 주소 //addConverterFactory -> 서버로 부터 데이터 받아와 원하는 데이터 타입으로 바꾸는 Converter 추가 val service = retrofit.create(RetrofitService::class.java) /* retrofit 안에 RetrofitService(서비스 클래스명) 넣어 service 만들어줌 * service 통해 데이터 통신 가능 */ //GET service.getStudentsList().enqueue(object: Callback<ArrayList<Person>> {//enqueue -> 해당 통신을 통신 대기줄에 올려 놓음 override fun onResponse( call: Call<ArrayList<Person>>, response: Response<ArrayList<Person>> ) { if(response.isSuccessful){ val personList = response.body()//데이터 가져옴 val statusCode = response.code()//Status Code 받아옴 val error = response.errorBody()//통신 성공했지만 에러 발생한 경우 에러 받아옴 val header = response.headers()//헤더 가져옴 }//통신 잘 된 경우 }//통신 성공한 경우 override fun onFailure(call: Call<ArrayList<Person>>, t: Throwable) { }//통신 실패한 경우 }) //POST val params = HashMap<String, Any>() params.put("name","홍길동") params.put("age", 20) params.put("intro","안녕하세요") service.createStudent(params).enqueue(object : Callback<Person>{ override fun onResponse(call: Call<Person>, response: Response<Person>) { if(response.isSuccessful){ val person = response.body() val name = person?.name } } override fun onFailure(call: Call<Person>, t: Throwable) { } }) //POST 요청 간단한 버전(HashMap 사용x) val person = Person(name="김철수", age=12, intro = "반갑습니다")//id값은 서버가 자동으로 생성함 service.createStudentEasy(person).enqueue(object : Callback<Person>{ override fun onResponse(call: Call<Person>, response: Response<Person>) { if(response.isSuccessful){ val person = response.body() val name = person?.name } } override fun onFailure(call: Call<Person>, t: Throwable) { } })
<서버에서 객체 받지 않는 경우 POST 요청하기>
@POST("baseURL 뒷부분") @FormUrlEncoded fun createStudent( @Field("value1") 변수명1: String, @Field("value2") 변수명2: String, @Field("value3") 변수명3: String ):Call<Person>
<Retrofit 장점>
- AsyncTask를 사용한 통신 방식이나 Volley에 비해 응답 속도 매우 빠름
- 동기/비동기 선택 가능
- Call 요청 취소 가능
<Retrofit 동기 실행 방법>
- 이 글을 처음 쓴게 꽤 오래 되었는데 쓴 당시에만 해도 Retrofit이 동기(execute() 사용), 비동기(enqueue() 사용) 방식으로 나뉘어져 있는지 몰랐다.. 그래서 서버로 부터 값을 받아 리턴하는 메서드 구현 당시에도 왜 비동기로 동작하는지 이해하지 못했다 오늘도 더 열심히 해야겠다고 다짐하고 간다..ㅜval okHttpClient = OkHttpClient.Builder() .readTimeout(5, TimeUnit.SECONDS) .connectTimeout(5, TimeUnit.SECONDS) .build() val retrofit = retrofit2.Retrofit.Builder().baseUrl("http://apis.data.go.kr") .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .client(okHttpClient) .build() val service = retrofit.create(RetrofitService::class.java) override fun getHoliday(): ArrayList<String> { var list = ArrayList<String>() runBlocking { CoroutineScope(Dispatchers.IO).async { val response = service.get_holiday().execute()//동기 실행 if (response.isSuccessful) { list = Json_to_List().HolidayJson_to_List(response.body().toString()) } }.await() } return list }//getHoliday
반응형'Android > Kotlin' 카테고리의 다른 글
[Android/Kotlin] ViewModel, LiveData, 화면 회전 처리 (0) 2022.07.11 [Android/Kotlin] 권한(Permission) (0) 2022.07.10 [Android/Kotlin] AsyncTask (0) 2022.07.09 [Android/Kotlin] Realm (0) 2022.07.08 [Android/Kotlin] Sharedpreference (0) 2022.07.08