본문 바로가기

안드로이드/코틀린

[Android] Coroutine + 위젯 업데이트 하기

반응형

현재 서비스중인 앱의 디비(Realm -> Room)를 이관하는 작업을 진행하고 있습니다. 단순 이관뿐만 아니라 코루틴을 사용한 비동기 처리  작업을 추가로 진행하면서  위젯을 업데이트 하는데 있어 겪었던 문제와 해결 방법에대해 공유드리겠습니다.

 

위젯 관련 다른 포스팅

>플로우

내부 디비 데이터 조회 -> 정제된 데이터 기반으로 위젯 뷰 업데이트 

플로우 자체는 간단하지만 오래된 코드를 분석해서 리펙토링 하는데 많은 시간이 소요됐고, 코루틴을 도입해 비동기로 데이터를 가져와 위젯을 업데이트 할때  엑티비티와 같은 일반 뷰들은 Main thread에서 업데이트 했을때 적용이 됐지만 위젯은 2가지 상황으로 나뉘어 적절하게 사용해야 합니다. 

 

1. 코루틴 메인 스레드로 뷰를 업데이트 할 경우

Dispatchers.Main 사용시 immediate 옵션을 사용하여야 위젯에 뷰가 업데이트 됩니다. 

                withContext(Dispatchers.Main.immediate + job) {
                    remoteViews.setViewVisibility(R.id.relativeLayout, View.VISIBLE)
                }

2. IO 스레드에서 가져온 데이터를 기반으로 일정 작업(데이터 정제등)을 마친 후 뷰를 업데이트 해야 할 경우 

위 1번 처럼 작업해도 작동하지 않았고, 직접적으로 widgetManager를 통해 updateAppWidget(int widgetId, View view) 메소드를 호출해줘야 합니다.

            withContext(Dispatchers.Main + job) {
            
                views.setTextColor(R.id.widget_line_color01, text_color)
                views.setTextColor(R.id.widget_line_color02, text_color)
                views.setTextColor(R.id.widget_line_color03, text_color)

                appWidgetManager.notifyAppWidgetViewDataChanged(widgetId, R.id.listview_appwidget)
                appWidgetManager.notifyAppWidgetViewDataChanged(widgetId, R.id.listview_appwidget2)

                appWidgetManager.updateAppWidget(widgetId, null)
                appWidgetManager.updateAppWidget(widgetId, views)
            }
            

특이하게 updateAppWidget(widgetId, null)을 호출해줬는데 이 경우는 리스트뷰에 해당하는 위젯을 사용중이고, adapter 역할인 'RemoteViewsService.RemoteViewsFactory' 의 데이터가 캐싱된 값을 사용해서 리플레시가 잘 안될 경우 사용합니다. 그렇지 않으면 onDataSetChanged를 호출하지 않습니다.

추가적으로 appWidgetManager.notifyAppWidgetViewDataChanged(int widgetI, int viewId)를 호출하면 비동기로 처리했더라도 위젯의 데이터가 정상적으로 변하는걸 알수 있습니다. 

 

위젯이 일반 뷰와 조금 다르게 작동하다보니 생각보다 많은 시간을 투자해서 리펙토링을 진행했습니다. 혹시 저와 비슷한 이슈로 문제를 겪으시는분은 댓글 달으시면 함께 고민해보도록 하겠습니다.  감사합니다.

 

 

반응형