모바일/Android

안드로이드 다른 쓰레드에서 프로그레스 휠 안 없어지는 현상

늘근이 2017. 7. 14. 18:34

자 한 쓰레드에서 프로그레스 휠을 돌린다. 

근데 프로그레스 휠을 돌리는 사태가 일어날때는 거의 네트워크 fetch가 일어나는 때이다. 

그런데 네트워크 로직은 안드로이드의 메인인 UI Thread에서는 동작할수 없다. 네트워크를 기다리고 있는동안 안드로이드가 멈추는 현상은 말이 안된다고 안드로이드를 만든 분들이 그렇게 생각했기 때문이다. 

자 그리고 네트워크를 태우고 다 태우고 결과를 받으면 프로그레스 휠을 그만 돌려야 하는 상황이 나온다.


만약 다행히도 다른 액티비티로 넘어간다면 프로그레스 휠은 원래 생성되었던 View에서 사라지지는 않았지만 어쨌든 붙은 곳이 어차피 사라지는 액티비티였기 때문에 굳이 hide를 해주지 않아도 사라진다. 


자 근데, 네트워크를 탈때 ProgressDialog등을 띄워놓고 네트워크가 끝나는 리스너에서 저걸 없애려고 단순히 로직을 짠다면 아래와 같은 에러문구가 떨어진다.


android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.


이를 없애기 위해서는 runOnUiThread를 부르면 되는것처럼 보이지만 안드로이드는 가끔 어벙하다. 동작하지 않을때가 더 많다. 여기에 대해서는 Looper, MessageQueue, Thread와 같은 키워드로 구글검색을 해보면 심오한 얘기가 나온다.


그렇다고 한다면 어떻게 지워야 하는가? 원래 고민하지 않아도 될 현상에 고민을 하게되는게 제일 시간아까운 결론이지만 꽤나 이것저것 해본결과 아래와 같이 그냥 progressDialog를 변수로 받아놓고, rootView도 변수로 받아놓는다.

그리고 이것을 가지고 리스터가 작동했을때 리스너 안에서 처리하면된다. 일반자바라면 리스너로 귀찮게 익명클래스로 작동하게 되고 코틀린이라면 심플하게 코드블럭을 작성해야 한다. 


자바는 final을 선언해야할것이고 코틀린은 val에다 집어넣으면 된다. 이제, rootView에다가 post()메서드로 프로그레스 휠을 지우는 로직을 실행시키게 한다. 현재 돌아가고 있는 쓰레드가 아니라 뷰에게 일임하는 것이다. 그 뷰는 코드 바깥에서 생성한 변수가 될것이고.



Sometimes, you need to hide active progress wheel after certain activity like networking. but the problem is, in Android,  you have to use sub thread to execute the code which is related to network. but you still need main thread (UI thread) to stop the annoying progress wheel. 

If you have trouble understanding difficult android messaging system, you should just use global variable to keep track of the bad progress wheel, and also with the root view that has the  progress wheel. 

sample code below. It is written in Kotlin. Code block wrapped with { } is the implementation of annoymous class with just one unimplemented method.  

The variable 'view' is responsible for the progress wheel, and post() is to tell original view, that has information about the thread that made progress wheel, to kill the wheel.