마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

소켓 통신 스레드 외에 다른 엑티비티에 화면 구성 스레드 동작 - 앱종료 문제

0 추천

포그라운드 서비스를 이용해 소켓 통신 스레드를 작동시키고, 소켓 통신을 통해 받은 값을 static으로 설정해 엑티비티에서 받은 값이 변경되도 바로 보일 수 있게 엑티비티 속에 변경되는 값으로 이미지 표시하는 부분을 스레드 속에 넣고 while문으로 계속 실행을 시켰습니다. 메인 엑티비티에 들어가면 포그라운드 서비스를 시작 시키고 메인 엑티비티에서 값 표시해주는 엑티비티로 이동하면 앱이 종료됩니다.  

스레드는 onResume에서 동작시키고, onDestory에서 종료시키고 while문의 값도 flase로 변경합니다.

가이드 찾아보니까 기본 스레드에서 네트워크를 요청하면 스레드가 응답을 받을 때까지 대기하거나 차단됩니다. 스레드가 차단되었기 때문에 OS는 onDraw()를 호출할 수 없고 앱이 정지되며 이에 따라 애플리케이션 응답 없음(ANR) 대화상자가 표시될 수 있습니다  라고 하던데 혹시 이것도 그런 문제인건가요? ㅠㅠ 

백그라운드에서 소켓 통신을 계속 유지시켜 받아오는 값이 변경되면 엑티비티에 보이게 하고 싶어서 엑티비티에서 스레드를 돌려 계속 UI를 변경시켰던건데 ㅠㅠ

좋은 방법 있으시면 알려주시면 감사하겠습니다. 

랄라룽 (380 포인트) 님이 2021년 7월 23일 질문

1개의 답변

0 추천
 
채택된 답변
모바일 앱에서 Thread를 크게 두가지로 구분할 수 있습니다.

- Main Thread(UI Thread)
- Worker Thread(Background Thread)

아마 기본 스레드는 Main Thread를 말하는 것 같은데요, 앱에는 Main Thread가 하나 존재하고 UI Thread도라고 합니다. 이유는 화면을 갱신하는 역할을 주된 임무로 하는 스레드이기 때문입니다. 안드로이드는 초당 60프레임 매 16ms마다 화면을 갱신합니다. 따라서 UI Thread에 화면을 갱신하는 일 외에 다른 일을 맡겨서는 안됩니다. 예를 들면 파일을 읽는다던지 네트워크 호출을 한다든지 등등.

그런데 님의 경우는 반대입니다. 님은 백그라운드 스레드를 생성하셨는데, 백그라운드 스레드에서 View에 접근해서 View를 업데이트 하려고 했기 때문에 계약위반이 된 겁니다. 화면의 갱신은 오직 UI Thread만이 가능합니다. 따라서 백그라운드 스레드에 있는 상태라면 UI Thread로 전환된 상태에서 View에 접근하셔야 합니다. Android에서는 Handler나, runOnUiThread등을 이용하셔서 Main Thread로 전환하신 다음 뷰에 대한 처리를 해주셔야 합니다.

따라서 이런 번거로움 때문에 보통은 Thread를 직접 생성하지는 않습니다. Rxjava(Java), Coroutine(Kotin)을 이용하여 처리해 주는 경우가 많습니다. 이 외에 스레드가 동시에 두개 이상이 동작할 때는 다른 스레드가 완료될 때까지 대기하거나 취소하는 등등의 Concurrency의 복잡성 때문에 스레드를 직접 사용할 수 있는 명료한 시나리오가 아니면 스레드를 직접 생성해서 핸들링하는 건 많은 시간을 투자해야 하는 일이 되기 쉽습니다.
spark (226,720 포인트) 님이 2021년 7월 23일 답변
랄라룽님이 2021년 7월 23일 채택됨
오늘도 답변 감사합니다.
백그라운드 스레드에서는 해당 엑티비티의 static으로 선언한 변수에 값만 담았는데 이것도 View에 접근한게 되는걸까요? ㅠㅠ
핸들러를 사용했는데 눌포인트가 자꾸나서 사용하지않았거든요 ㅠㅠㅠ
구글링을 하다가 스레드로 돌리지않고 대신 AsyncTask를 사용하니 통신은 잘되는데 엑티비티에 변경된 값이 표시가 안됩니다. 더 찾아보려고 하는데 AsyncTask 사용이 문제가 될까요?
변수가 뷰가 아니라면 괜찮을 겁니다. static은 가능한 사용하지 마세요, 모바일에서는 정말 찾기 힘든 버그의 원상입니다. 그리고 맞습니다. Handler는 사용 후에 꼭 해제해야 하는 등의 주의할 점이 많습니다.
AsyncTask는 onPostExecute 메소드가 자동으로 Main Thread로 전환하게 내부적으로 처리해 줍니다. 하지만 deprecated 되어서 가능하면 사용하지 않으시는 것이 좋습니다. Main Main Thread에 접근하기 위해서 Looper를 통해 Main Thread를 얻어오는 방법도 있습니다. 한번 검색해 보세요.
AsynTask의 소스코드를 확인해 보시면 좋겠네요. 어떻게 백그라운드 쓰레드에서 메인쓰레드로 전환하고 있는지 알 수 있겠네요.
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/AsyncTask.java
답글 감사합니다 또 시도해볼게요!!
...