오랜만에 구글 플레이 콘솔에 들어가서 이것저것 구경하고 있었는데 이런게 눈에 띄었다.
공지가 된지는 상당한 시간이 지났지만, 뒤늦게 확인을 하게 되었다.
최근 플레이 스토어에 출시를 목적으로 진행하고 있는 프로젝트의 targetSdkVersion
이 29로 설정되어 있었기 때문에, 이를 30으로 수정하여 마저 구현해야 했다.
그런데 API 30 수준부터는 Handler
의 생성자 2가지가 deprecated 되었고, 이를 수정할 때 필요한 내용을 정리하고자 이번 글을 작성하게 되었다.
아래의 모든 내용은 stackoverflow의 게시글을 참고했으며, 해당 게시물의 링크는 아래와 같다.
https://stackoverflow.com/questions/61023968/what-do-i-use-now-that-handler-is-deprecated
Handler
가 생성되는 동안, Looper
가 암묵적으로 선택되면 여러가지 버그가 발생할 수 있다고 한다.
이러한 가능성을 차단하기 위해서는 명시적으로 Looper
를 선언해야 하므로, Handler()
와 Handler(Handler.Callback)
이 deprecated 된 것 같다.
정확하고 자세한 내용은 공식 문서를 참고하면 될 것 같다.
https://developer.android.com/reference/android/os/Handler#Handler()
Handler
를 사용하는 이유로는 여러가지가 있겠지만, 이 게시글에서는 background thread에서 작업을 수행하고, 그 결과를 UI에 반영하기 위해서 Handler
를 사용한다.
우선 지금까지 사용했던 Thread
와 Handler
의 구조부터 살펴보자.
val myHandler: MyHandler = MyHandler()
inner class MyHandler : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
val bundle: Bundle = msg.data
if (!bundle.isEmpty) {
// UI 작업은 여기에
}
}
}
inner class MyThread : Thread() {
var stopFlag = false
override fun run() {
while (!stopFlag) {
val message = myHandler.obtainMessage()
val bundle: Bundle = Bundle()
// background thread에서 수행할 작업은 여기에
message.data = bundle
myHandler.sendMessage(message)
sleep(300)
}
}
fun threadStop(flag: Boolean) {
this.stopFlag = flag
}
}
background에서 일정한 주기마다 작업을 반복하고, 작업의 결과를 UI에 반영하기 위한 Thread
와 Handler
의 구조이다. (물론 이 코드보다 효율이 더 좋은 코드는 많겠지만..)
이제 이 코드에서 Handler()
를 Handler(Looper.getMainLooper())
로 수정하기만 하면 deprecated 문제는 해결된다!
아래는 수정한 코드이다.
val myHandler: MyHandler = MyHandler()
inner class MyHandler : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
val bundle: Bundle = msg.data
if (!bundle.isEmpty) {
// UI 작업은 여기에
}
}
}
inner class MyThread : Thread() {
var stopFlag = false
override fun run() {
while (!stopFlag) {
val message = myHandler.obtainMessage()
val bundle: Bundle = Bundle()
// background thread에서 수행할 작업은 여기에
message.data = bundle
myHandler.sendMessage(message)
sleep(300)
}
}
fun threadStop(flag: Boolean) {
this.stopFlag = flag
}
}
이 외에도 맨 처음에 언급했던 stackoverflow 게시글을 읽어보면 Excutor
를 사용하는 방법도 있지만... 처음 보는 내용이기에 나중에 더 알아봐야 할 것 같다.