App/Android

[Android][공부기록] Main Thread란?(+ 실습으로 알아보기)

앙두딘 2022. 8. 11. 12:46

Main Thread란?

안드로이드 어플리케이션이 실행되면 안드로이드 시스템은 ‘하나의 실행 스레드’로 어플리케이션의 프로세스를 실행한다.

어플리케이션의 구성 요소가 생성될 때 별도의 스레드가 생성되는 것은 아니며, 앞서 말한 하나의 실행 스레드에서 실행되는데 이를 Main thread라고 한다.

 

Main Thread가 하는 일?

안드로이드 시스템에 의해 생성된 이 Main thread는 화면 구성에 관한 역할을 담당한다.

예를 들어 Button, CheckBox, TextView 등의 UI도구 키트 구성 요소를 생성/조작하였을 때 상호작용하는 스레드가 Main Thread이다.

그래서 MainThread를 UI Thread라고도 한다.

 

APK의 스레드를 출력해보면 메인스레드 외에도 바인더 스레드와 그 외 런타임 내부 스레드들이 존재한다.

  • 바인더 스레드: 프로세스간 통신을 위해 사용됨

빈 액티비티만 존재하는 어플리케이션일지라도 이렇게 여러 스레드들을 기본적으로 생성하고 있다.

 

더보기

[궁금해서 찾아본 내용]
(ps PID -t 명령어로 스레드를 출력해보면 나오는 결과 중 WCHAN이라는 항목이 의미하는 바가 궁금했다)

 

WCHAN이란?

Wait Channel 프로세스가 기다리고 있는 커널 루틴으로 즉, 기다리고 있는 이벤트의 주소이다.

 

Main Thread에 대해서 좀 더 알아보자.

앱을 실행했을 때, 버튼을 누르거나 화면 터치를 했는데 반응성이 떨어지면 유저는 답답함을 느낄 것이다.

그리고 간혹 ANR(Application Not Responding)이 발생하여 앱이 강제종료되는 것을 본 경험도 있을 것이다.

  • ANR은 앱의 UI스레드가 너무 오랫동안 차단되면(5초간 응답이 없을 경우) 트리거된다.

반응성은 Main thread와 실제 작업이 실행되는 스레드 간 관계에 관련이 있다.

예를 들어 비디오를 다운로드하는 작업을 Main Thread에 구현했다면, 다운로드가 끝날때까지 UI는 멈추어 있을 것이다.

따라서 반응성 좋은 어플리케이션을 구현하려면 시간이 오래 걸리는 작업을 Main Thread가 아닌 별도의 스레드에서 동작하도록 구현하면 된다

 

안드로이드 UI 도구 키트는 스레드로부터 세이프할까?

(== 여러 스레드에서 사용해도 정상적으로 동작할까?)

안드로이드 UI 도구 키트는 스레드로부터 세이프하지 않다.

따라서 UI Thread 외의 별도 생성한 Thread에서 UI 구성요소를 조작하는 것은 허용되지 않는다.

UI구성요소는 모두 UI thread에서 조작되어야하고, 결국 UI입장에서 보면 단일 스레드로 동작하는 구조가 된다.

따라서 UI Thread에서 시간이 오래 걸리는 작업을 수행하는 것은 그 작업이 수행되는 동안 UI 업데이트가 지연되고있다는 것을 의미한다.

 

간단한 앱을 만들어 확인해보았다.

package com.example.uithreadtest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View

class MainActivity : AppCompatActivity() {
    val TAG = "download"
    var isDownloading = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    fun onDownload(view:View){
        isDownloading = true
        Log.d(TAG, "Start Downloading")
        for(i in 1 until 11){
            if(!isDownloading)  break
            else{
                try {
                    Thread.sleep(1000)
                    Log.d(TAG, "Downloading.. ${i*10}%")
                }catch (e:InterruptedException){
                    e.printStackTrace()
                }
            }
        }
        isDownloading = false
    }

    fun onCancel(view:View){
        Log.d(TAG, "Downloading Canceled")
        isDownloading = false
    }
}

 

Download 버튼을 누른 뒤, Cancel버튼을 여러번 누르면 아래와 같이 ANR이 발생한다.

5초 이상 UI Thread에 응답이 없었기 때문!

발생하지 않도록 하기 위해서는 다운로드 동작을 다른 스레드로 분리해야 한다.

다른 스레드를 생성해 분리해보자.

package com.example.uithreadtest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View

class MainActivity : AppCompatActivity() {
    public val TAG = "DownloadThreadTest"
    var isDownloading = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    fun onDownload(view:View){
        isDownloading = true
        Thread(Runnable {
            Log.d(TAG, "Start Downloading")

            for(i in 1 until 11){
                if(!isDownloading){
                    break
                }
                try {
                    Thread.sleep(1000L)
                    Log.d(TAG, "Downloading.. ${i*10}%")
                }catch (e:InterruptedException){
                    e.printStackTrace()
                }
            }
            Log.d(TAG, "Completed!")
            isDownloading = false
        }).start()
    }

    fun onCancel(view:View){
        if(isDownloading)   {
            Log.d(TAG, "Downloading Canceled")
            isDownloading = false
        }
    }
}

이와 같이 Thread를 분리해서 동작시킬 경우, Cancel 버튼을 눌렀을 때 바로 멈추는 것을 확인할 수 있다.

 


출처)

https://codetravel.tistory.com/9

 

안드로이드 메인 스레드(Android Main Thread 또는 UI Thread)

안드로이드 어플리케이션이 실행되면 안드로이드 시스템은 하나의 실행 스레드로 어플리케이션의 프로세스를 실행합니다. 어플리케이션의 구성 요소가 생성될 때 별도의 스레드가 생성되는

codetravel.tistory.com