
이전 포스트에서 제시한 한번에 RecyclerView 내부의 EditText의 텍스트를 실시간으로 반영하는 기능(이하 실시간 연결 기능)이 작동하지 않는 문제를 코루틴을 사용하여 해결했다.

로그를 여러개 만들어 상황을 확인해보았다.
코드 상 함수 호출 순서는 아래와 같지만 updateMan() 내부의 adapter?.notifyItemRangeChanged(0,8)이 온클릭 함수를 종료하고 실행되는 상황이다.
그렇기 때문에 wholeCenterUpdate() 이후 RecyclerView의 bind함수가 실행되어 이전에 실행한 wholeCenterUpdate()의 의미가 없어졌다.
binding.btnEdit.setOnClickListener {
⁝
updateMan() # Mandalart 정보 업데이트
wholeCenterUpdate() # 실시간 연결 기능
⁝
}
private fun updateMan(){
Log.d("GridTest", "call updateMan")
binding.mainGrid.adapter?.notifyItemRangeChanged(0, 8)
Log.d("GridTest", "done updateMan")
}
fun wholeCenterUpdate(maingrid: RecyclerView){
Log.d("GridTest", "call wCUpdate")
val cenM9 = maingrid[ND.MANCENTER] as RecyclerView
for (i in ND.MANSTART .. ND.MANEND){
if (i == ND.MANCENTER) continue
val subM9 = maingrid[i] as RecyclerView
eachCenterUpdate(subM9[ND.MANCENTER] as EditText, cenM9[i] as EditText)
}
Log.d("GridTest", "done wCUpdate")
}
fun eachCenterUpdate(subCenterET: EditText, centerSubET: EditText) {
Log.d("GridTest", "call eCUpdate")
val scTextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
centerSubET.text = s
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
}
val csTextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
subCenterET.removeTextChangedListener(scTextWatcher)
subCenterET.text = s
subCenterET.addTextChangedListener(scTextWatcher)
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
}
subCenterET.addTextChangedListener(scTextWatcher)
centerSubET.addTextChangedListener(csTextWatcher)
Log.d("GridTest", "done eCUpdate")
}
(※틀린 정보가 있을 수 있습니다※)
로그를 보고 들은 생각은 updateMan() 내부의 notifyItemRangeChanged()가 다른 Thread에서 작동하는것 같았다.
처음의 생각은 동기화를 사용하여 updateMan()이 완전히 실행될 때까지 onClick 함수 내부에서 대기를 해볼 생각이었다.
그래서 코루틴을 사용해서 코루틴 내부에 updateMan을 넣어 여러가지 실험을 해보았지만 결과는 달라지지 않았다.
그래서 wholeCenterUpdate()도 같이 코루틴 내부에 넣었다 뺐다하며 실험을 해보았는데 결과적으로 해결 방안은 코루틴 내부에서 wholeCenterUpdate()만 호출하는 것이었다.
기본적으로 안드로이드에서 UI를 담당하는 스레드인 Main Thread(=UI Thread)는 한 스레드만 존재했고 UI 이벤트가 발생하면 이벤트를 이벤트 처리 큐로 관리하여 FIFO 형식으로 관리했다.
따라서 notifyItemRangeChanged()를 호출하여 새로운 UI 이벤트가 발생되면 현재 Main Thread에서 진행되고 있는 OnClickListener가 전부 끝난 후 notifyItemRangeChanged()가 실행되는 것이었다.
여기서 다시 해결방안을 보면 코루틴을 사용하여 wholeCenterUpdate()를 Main Thread 큐에 새롭게 넣어 notifyItemRangeChanged() 이후에 wholeCenterUpdate()가 작동하도록 한것이었다.

binding.btnEdit.setOnClickListener {
⁝
updateMan() # Mandalart 정보 업데이트
CoroutineScope(Dispatchers.Main).launch {
wholeCenterUpdate() # 실시간 연결 기능
}
⁝
}
위 처럼 기능상 updateMan() 이후에 호출되어야할 함수를 CoroutineScope(Dispatchers.Main).launch로 감싸주기만 하면 된다.
해당 문제에 대해서 기능적으론 잘 해결했지만 정보에 오류가 있을 수 있습니다.
댓글로 정정해주시면 감사하겠습니다.