Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- 유튜브
- Zsh
- exoplayer cache
- getChangePayload
- android
- android ktor
- ktor api call
- list map
- ExoPlayer
- 스피너
- DiffUtil.ItemCallback
- ChatGPT
- FastAPI
- android custom view
- build with ai
- video caching
- 독서
- ktor client
- AWS EC2
- doc2vec
- Python
- ListAdapter
- kotlin collection
- 안드로이드
- llm
- map
- android exoplayer
- 시행착오
- kotlin list
- ListAdapter DiffUtil
Archives
- Today
- Total
버튼 수집상
[안드로이드] 가변적인 json 키를 동일한 클래스로 파싱하기 본문
배경
같은 종류의 데이터가 각기 다른 json 키 이름으로 들어오는 api 가 있었다.
구글의 gson 라이브러리는 json 키와 데이터 클래스 변수명을 1:1로 매핑시키므로 별도의 처리가 필요했다.
예시
데이터 클래스
data class TestResponse(
// 키 이름이 다른 json 값들을 읽어서 List에 add.
val areaList: List<AreaData>?
) {
data class AreaData(
@SerializedName("itemType") val itemType: String?,
@SerializedName("imagePath") val imagePath: String?
)
}
응답값 json
{
"banner1" : {
"itemType" : "banner1",
"imagePath" : "banner1"
},
"banner2" : {
"itemType" : "banner2",
"imagePath" : "banner2"
},
"tab1" : {
"itemType" : "tab1",
"imagePath" : "tab1"
},
"goods1" : {
"itemType" : "goods1",
"imagePath" : "goods1"
},
"goods2" : {
"itemType" : "goods2",
"imagePath" : "goods2"
},
"tab2" : {
"itemType" : "tab2",
"imagePath" : "tab2"
}
}
방법
먼저 커스텀 TypeAdapter 를 만들어준다
class AreaDataTypeAdapter : TypeAdapter<TestResponse>() {
override fun write(out: com.google.gson.stream.JsonWriter?, value: TestResponse?) {
// not needed in this case
}
override fun read(reader: com.google.gson.stream.JsonReader?): TestResponse {
val list = mutableListOf<TestResponse.AreaData>()
var itemType: String? = null
var imgPath: String? = null
reader?.let {
reader.beginObject()
while (reader.hasNext()) {
val key = reader.nextName()
// json 키 패턴을 regex로 정의
val pattern = Regex("(banner|sns|goods|gallery|tab)\\d+")
if (pattern.matches(key)) {
reader.beginObject()
while (reader.hasNext()) {
val innerKey = reader.nextName()
when (innerKey) {
"itemType" -> itemType = reader.nextString()
"imagePath" -> imgPath = reader.nextString()
else -> reader.skipValue()
}
}
reader.endObject()
list.add(TestResponse.AreaData(itemType, imgPath))
} else {
reader.skipValue()
}
}
reader.endObject()
}
return TestResponse(list)
}
}
만든 TypeAdapter 를 register 해준다.
1) retrofit에 붙이기
val gson = GsonBuilder()
.registerTypeAdapter(TestResponse::class.java, AreaDataTypeAdapter())
.create()
return Retrofit.Builder()
.baseUrl(BASE_DOMAIN)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build()
.create(ApiService::class.java)
2) json 로컬데이터를 쓸 때
val jsonString = getJsonFileToString("jsons/test.json", BaseApp.context)
val gson = GsonBuilder()
.registerTypeAdapter(TestResponse::class.java, AreaDataTypeAdapter())
.create()
val data = gson.fromJson(jsonString, TestResponse::class.java)
빌드해보고 에러가 난다면
json 키와 데이터 타입을 맞게 처리했는지 확인.
list 나 클래스처럼 뎁스가 깊어지면 그에 대한 처리도 필요.
참고
Android - Convert json which has uncertain keys to map using kotlin
I have a json like this. I need to convert it to data class { "0": { "id": "111", "type": "1", "items": [ ...
stackoverflow.com
728x90
'TIL - 안드로이드' 카테고리의 다른 글
[안드로이드] 스크롤 상단에 margin 적용한 sticky view 만들기 (0) | 2023.05.02 |
---|---|
[안드로이드] 스피너 커스텀UI 만들기 (두 줄 리스트 스피너) (0) | 2023.05.02 |
[안드로이드] Invisible된 액티비티가 onStop을 타지 않는 이슈 (0) | 2023.02.22 |
[안드로이드] 액티비티 미리 로드하기 (0) | 2023.01.05 |
[안드로이드] Spinner 아이템 선택 안 하고도 onItemSelectedListener 를 타는 문제 (0) | 2022.12.08 |