본문 바로가기
개발/Java

Java & Swift _ runOnUiThread , view.post , handler, DispatchQueue.... 의 차이

by JunsC 2024. 9. 12.
728x90

작업을 하면서 성능 및 메모리상 구조적으로 좋은쪽으로 짜려고 하다보니 궁금한게 많아져서 끄적끄적이고 있다.

 

우선 위의 3가지는 겉으로 보기에는 같은 기능을 가지고 있지만 세부적으로 보면 용도와 그 기능들이 차이가 있다!!

 

1. runOnUiThread(Runnable)

개요

  • Activity에서 UI 관련 작업을 메인(UI) 스레드에서 실행하도록 강제할 때 사용합니다.
  • 내부적으로 Handler를 사용하여 Looper.getMainLooper()를 통해 실행됩니다.

사용법

runOnUiThread(new Runnable() { 
	@Override 
	public void run() { 
	textView.setText("UI 업데이트"); 
		} 
	});

특징

  • Activity에서 직접 호출 가능 (this.runOnUiThread())
  • UI 업데이트를 위해 간단한 코드라면 사용하기 편리함
  • Activity가 종료되었을 때 호출하면 IllegalStateException이 발생할 가능성이 있음

동작: 현재 스레드가 UI 스레드가 아닐 경우, UI 스레드에서 작업을 즉시 실행. 현재 스레드가 이미 UI 스레드인 경우, 작업은 즉시 실행.

용도: UI 스레드에서 작업을 실행해야 하지만 현재 스레드가 UI 스레드가 아닌 경우에 사용

성능: 즉시 실행되므로 지연이 없음.

메모리: 메모리 사용량에 큰 영향을 미치지 않음. UI 스레드에서 직접 작업을 수행.

 

 

2. View.post(Runnable)

개요

  • 특정 View가 UI 스레드에서 실행되도록 예약하는 방법
  • View가 attach되어 있는 경우 실행됨

사용법

textView.post(new Runnable() { 
    @Override 
    public void run() { 
    textView.setText("UI 업데이트"); 
    } 
});

특징

  • View가 생성된 후(UI 트리가 존재할 때) 실행됨
  • View가 attach되지 않은 상태에서 실행하면 실행되지 않을 수 있음
  • 특정 View에 연결된 UI 업데이트를 위해 적절함

동작: 지정된 View의 UI 스레드의 메시지 큐에 작업을 추가. View가 화면에 표시된 후 작업을 실행.

용도: View가 화면에 표시된 후에 작업을 실행할 필요가 있을 때 사용. 예를 들어, 레이아웃이 완전히 그려진 후에 작업을 실행해야 하는 경우 유용.

성능: 작업이 UI 스레드의 메시지 큐에 추가되므로, 즉시 실행되지 않고 약간의 지연이 있을 수 있음.

메모리: 지연된 작업이 메시지 큐에 저장되므로 메모리 사용량이 약간 증가할 수 있음.

 

 

3. Handler(Looper.getMainLooper()).post(Runnable)

개요

  • Handler를 이용해 UI 스레드에서 실행되도록 예약하는 방법
  • Handler는 메시지 큐를 사용하여 실행 예약을 조정할 수 있음

사용법

new Handler(Looper.getMainLooper()).post(new Runnable() { 
    @Override 
    public void run() { 
    textView.setText("UI 업데이트"); 
    } 
});

특징

  • runOnUiThread()와 유사하지만 Handler 객체를 직접 사용하여 관리 가능
  • postDelayed()를 사용하여 일정 시간 이후 실행 가능
  • removeCallbacks()를 통해 예약된 실행을 취소할 수도 있음

동작: Handler를 사용하여 메시지 큐에 작업을 추가합니다. Handler는 지정된 Looper와 연관된 스레드에서 작업을 실행.

용도: 특정 스레드에서 작업을 지연시키거나 큐에 작업을 추가할 때 사용. Handler를 사용하여 메인 스레드에서 작업을 지연시키려면 Looper.getMainLooper()를 사용.

성능: Handler를 사용하여 메시지 큐에 작업을 추가하므로, 작업이 실행되기까지 약간의 지연이 있을 수 있음.

메모리: Handler가 메시지 큐에 작업을 추가하기 때문에 메모리 사용량이 증가할 수 있으며, 특히 많은 작업을 큐에 추가할 때 메모리 관리에 주의.

 

 

주요 차이점

  1. 동작 시점:
    • runOnUiThread: 현재 스레드가 UI 스레드가 아니면, UI 스레드에서 즉시 실행합니다.
    • View.post: 지정된 View의 UI 스레드의 메시지 큐에 작업을 추가하여 View가 화면에 표시된 후 실행합니다.
    • Handler: 지정된 Looper와 연관된 스레드에서 작업을 큐에 추가하고, 큐에서 작업을 실행합니다.
  2. 용도:
    • runOnUiThread: UI 스레드에서 작업을 즉시 실행해야 할 때.
    • View.post: View가 화면에 표시된 후 작업을 실행해야 할 때.
    • Handler: 특정 스레드에서 작업을 지연시키거나 큐에 추가해야 할 때.
  3. 성능 및 메모리:
    • runOnUiThread: 즉시 실행되므로 지연이 없음. 메모리 오버헤드가 거의 없음.
    • View.post: 약간의 지연이 있을 수 있음. 메모리 오버헤드가 약간 있을 수 있음.
    • Handler: 지연이 있을 수 있으며, 많은 작업을 큐에 추가할 경우 메모리 관리에 주의 필요.

결론

  • 즉시 UI 스레드에서 작업을 실행해야 하는 경우: runOnUiThread를 사용하는 것이 적합.
  • View의 상태에 따라 작업을 지연시키고 싶은 경우: View.post를 사용할 수 있음.
  • 특정 스레드에서 작업을 지연시키거나 큐에 추가할 필요가 있는 경우: Handler를 사용하는 것이 적합.

■ 정리

  • 간단한 UI 변경 → runOnUiThread()
  • 특정 View에 대한 작업 → View.post()
  • 예약 실행이 필요하거나 백그라운드 작업에서 UI 변경 → Handler.post()

 

 

그럼 Swift 에 대해서도 알아보도록 하자

 

1. DispatchQueue

Swift에서는 DispatchQueue를 사용하여 동시성을 관리하고, 다른 스레드에서 코드를 실행할 수 있습니다. 메인 스레드에서 코드를 실행하려면 다음과 같이 사용할 수 있습니다.

메인 큐

메인 스레드에서 코드를 실행하려면 다음 코드를 사용합니다:

DispatchQueue.main.async {
    // UI 업데이트 코드를 여기에 작성합니다.
}

예시:

DispatchQueue.main.async {
    self.myLabel.text = "업데이트된 텍스트"
}

2. performSelector(onMainThread:)

또 다른 방법으로 performSelector(onMainThread:with:waitUntilDone:)를 사용하여 메인 스레드에서 코드를 실행할 수 있습니다.

예시:

self.performSelector(onMainThread: #selector(updateUI), with: nil, waitUntilDone: false)

@objc func updateUI() {
    // UI 업데이트 코드를 여기에 작성합니다.
    myLabel.text = "업데이트된 텍스트"
}

3. Timer

일정 시간 간격으로 반복적으로 실행되는 코드를 원할 경우 Timer를 사용할 수 있습니다.

예시:

Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
    // 메인 스레드에서 실행되는 코드
    self.myLabel.text = "1초마다 업데이트"
}

4. OperationQueue

작업을 관리할 때 OperationQueue를 사용할 수 있으며, 일부 작업이 메인 큐에서 실행되도록 지정할 수 있습니다.

예시:

let operationQueue = OperationQueue()
operationQueue.addOperation {
    // 백그라운드 작업
    let result = performLongRunningTask()

    // 메인 스레드에서 UI 업데이트
    DispatchQueue.main.async {
        self.myLabel.text = result
    }
}

요약

  • DispatchQueue.main.async를 사용하여 메인 스레드에서 코드를 실행합니다.
  • 구식 코드베이스에서는 performSelector(onMainThread:with:waitUntilDone:)를 사용할 수 있습니다.
  • 반복 작업에는 Timer를 사용합니다.
  • 복잡한 작업 종속성을 관리할 때는 OperationQueue를 사용합니다.

이러한 개념은 Android의 runOnUiThread, View.post, Handler와 유사하며, Swift에서도 UI 업데이트와 비동기 작업을 효과적으로 관리할 수 있도록 도와줍니다.

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."