서버에서 받는 값은 전체 리스트밖에 없었고, 서버 통신으로 받아온 정보를 담은 리사이클러뷰의 아이템을 클릭하면 조회한 데이터를 넘겨 수정 화면에 불러와야했다.
TemplateMyFragment | AddMyTemplateActivity |
---|
위의 사진을 보면 아마 이해가 더 쉬울 것이다.
리사이클러뷰 아이템 2개 중에서, 아래를 클릭하면 제목, 카테고리, 기간, Todo 리스트를 수정 화면으로 넘겨야 했다.
데이터를 넘기는 화면이 Activity였으면 Bundle에 데이터를 담아 argument에 넣어주고, 데이터를 받는 fragment에서 argument에 있는 데이터를 꺼내서 사용했을텐데 ..
(어라 잠만, 내가 왜 안 썼더라..?)
2023.11.30 업데이트
👉🏻 [Android/Kotlin] 화면을 이동할 때 데이터를 전달하는 방법
위 글을 함께 참고하면 좋을 것 같다.
companion object {
private const val KEY_PREFS = "template"
private const val KEY_DATA = "template_data"
private const val KEY_EDITABLE = "editable"
private const val KEY_IDX = "templateIdx"
}
private fun savePref(dataSet: Template) {
val spf = requireActivity().getSharedPreferences(KEY_PREFS, Context.MODE_PRIVATE)
val editor = spf.edit()
val gson = Gson()
val json = gson.toJson(dataSet) // 템플릿 데이터 변환
editor.putString(KEY_DATA, json)
editor.putBoolean(KEY_EDITABLE, true)
editor.putInt(KEY_IDX, dataSet.id)
editor.apply()
Log.d("debug", "Data saved")
}
참고로 Template은 서버에서 받아오는 데이터 클래스로,
data class Template(
@SerializedName("ID") val id: Int = 0,
@SerializedName("CATEGORY") val category: Category,
@SerializedName("TITLE") val title: String = "",
@SerializedName("DESC") val desc: String = "",
@SerializedName("SCHEDULE") val schedule: Int = 0,
@SerializedName("START_DATE") val start_date: String = "",
@SerializedName("END_DATE") val end_date: String = "",
@SerializedName("TODO") val todo: ArrayList<TemplateTodoList>,
@SerializedName("CURSOR") val cursor: String = ""
)
data class TemplateTodoList(
@SerializedName("ID") val id: Int? = 0,
@SerializedName("TODO") val todo: String? = ""
)
이렇게 구성된다.
private fun initRecyclerView(result: ArrayList<Template>) {
// adapter
binding.myTemplateRv.apply {
val templateAdapter = MyTemplateRVAdapter(result)
templateAdapter.setData(-1)
templateAdapter.setItemClickListener(object: MyTemplateRVAdapter.MyItemClickListener {
// item click
override fun onItemClick(template: Template, position: Int) {
Log.d("TemplateMyFragment", "편집 화면으로 이동")
// 데이터 저장
savePref(template)
// MY템플릿 수정 화면으로 이동
startActivity(Intent(activity, AddMyTemplateActivity()::class.java))
}
})
binding.myTemplateRv.adapter = templateAdapter
binding.myTemplateRv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
}
}
이 initRecyclerView
함수는 템플릿 조회 서버 통신이 성공했을 때 파라미터로 그 response를 넣어서 호출한다. (아래 참고)
override fun onGetTemplateSuccess(result: ArrayList<Template>) {
initRecyclerView(result)
}
리사이클러뷰 어댑터 코드는 참고 삼아 ..
class MyTemplateRVAdapter(val result: ArrayList<Template>) : RecyclerView.Adapter<MyTemplateRVAdapter.ViewHolder>() {
interface MyItemClickListener: NewGoalView {
fun onItemClick(template: Template, position: Int)
}
private lateinit var mItemClickListener: MyItemClickListener //전달받은 리스너 객체를 저장할 변수 (어댑터 내에 사용)
fun setItemClickListener(itemClickListener: MyItemClickListener) {
mItemClickListener = itemClickListener
} //외부에서 전달받을 수 있는 함수
inner class ViewHolder(val binding: ItemAddTemplateBinding, val context: Context) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: Template){
with(binding){
val period = item.schedule / 7
itemTemplateWeeksTv.text = "${period}주"
itemTemplateTitleTextTv.text = item.title
itemTemplateDetailTextTv.text = item.desc
itemTemplatePeriodStartTv.text = item.start_date.replace("-", ".")
itemTemplatePeriodEndTv.text = item.end_date.replace("-", ".")
val itemTemplateTodoTvList = listOf(
itemTemplateTodo1Tv,
itemTemplateTodo2Tv,
itemTemplateTodo3Tv,
itemTemplateTodo4Tv,
itemTemplateTodo5Tv,
itemTemplateTodo6Tv
)
val size = item.todo.size
// 조회한 투두 개수만큼 아이템에 넣어줌
for ( i:Int in 0 until size) {
itemTemplateTodoTvList[i].visibility = View.VISIBLE
itemTemplateTodoTvList[i].text = item.todo[i].todo
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(
ItemAddTemplateBinding.inflate(LayoutInflater.from(parent.context), parent, false),
parent.context
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(result[position])
// 전체 아이템 클릭
holder.itemView.setOnClickListener {
mItemClickListener.onItemClick(result[position], position)
}
}
override fun getItemCount(): Int = result.size
}
// 받는 쪽
private fun loadPref() {
val spf = getSharedPreferences(KEY_PREFS, Context.MODE_PRIVATE)
if (spf.contains(KEY_DATA)) {
val gson = Gson()
val json = spf.getString(KEY_DATA, "")
try {
// 데이터에 타입을 부여하기 위한 typeToken
val typeToken = object : TypeToken<Template>() {}.type
// 데이터 받기
val data: Template = gson.fromJson(json, typeToken)
// 뷰에 받아온 데이터 값 넣어주기
with(binding) {
// 카테고리
categoryId = data.category.id
addMyTemplateCategoryEt.setCompoundDrawablesWithIntrinsicBounds(categoryImgList[categoryId], 0, R.drawable.ic_arrow_down, 0)
addMyTemplateCategoryEt.setText(categoryNameList[categoryId])
// 제목
addMyTemplateGoalEt.setText(data.title)
// 설명 (선택)
addMyTemplateDescEt.setText(data.desc)
// 기간
addMyTemplatePeriodEt.setText("${data.schedule/7}주")
// 투두
val size = data.todo.size
for( i:Int in 0 until size ) {
todoList[i].visibility = View.VISIBLE
todoList[i].setText(data.todo[i].todo)
}
}
} catch (e: JsonParseException) { // 파싱이 안 될 경우
e.printStackTrace()
}
Log.d("debug", "Data loaded")
}
}
onCreate() 에서 위의 loadPref()
함수를 호출해주면 됨
그럼 앞에서 봤던
TemplateMyFragment | AddMyTemplateActivity |
---|
화면이 완성된다.
잘봤습니다.