안드로이드

[안드로이드] Thread간 통신 예제 - 실행 시간 표시

디벨로펄 2023. 3. 29.
반응형
 

[안드로이드] Thread, Thread간 통신/ Handler, Looper의 개념

참고 1. 성빈랜드님 글 안드로이드 스레드에 대해 한 번에 알아보자 AndroidDeepDive #1 — thread, message, message queue, looper, handler sungbin.land 2. https://hungseong.tistory.com/26 [Android, Kotlin] 멀티 스레드 간 통신

developerpearl.tistory.com

Thread, Handler, Looper에 대해서 알아보았는데, 이제  얘네를 직접 구현해보도록하겠습니다.

 

예제로는 버튼 Start를 누른 후부터의 시간 재는 기능으로 구현하겠습니다.

 

워커스레드 : Main Thread외에 추가된 Thread 구현

 

Toast메세지UI 수정을 위해서 context와 TextView를 parameter로 받아왔습니다.

 

** 여기서 중점으로 봐야하는 부분은 Handler(Looper.getMainLooper()).post 입니다.

여기 내부에서 UI 부분을 처리할 수 있습니다.

class TimeCountThread(val handler: Handler, val context : Context, val tv : TextView) : Thread() {
    private var time = 0

    override fun run() {
        while(true) {

            // 메세지 객체 전달.
            val msg = handler.obtainMessage()
            val bundle = Bundle()
            bundle.putInt("key", time)
            msg.data = bundle
            handler.sendMessage(msg)

            // post로 runnable 실행
            Handler(Looper.getMainLooper()).post {
                Toast.makeText(context, "시작 Tread : ${this.name}", Toast.LENGTH_SHORT).show()
                // 다른 thread에서 UI에 접근하려하면 ANR발생한다.(Application Not Response
                tv.text = "$time 초"
                time += 5
            }
            sleep(5000)
        }
    }
    fun stopThread(){
        Handler(Looper.getMainLooper()).post{
            Toast.makeText(context, "종료 Tread : ${this.name}", Toast.LENGTH_SHORT).show()
            tv.text = "준비중"
        }
    }
}

* Fragment 내부에 구현했기때문에, onViewCreated 내부는 다음과 같습니다.

class FirstFragment : Fragment() {

    private var _binding: FragmentFirstBinding? = null
    private var timeCountThread: TimeCountThread? = null

    private val handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            // 메시지 처리 작업 수행
            println("메세지 처리 작업 수행")
            println(msg.data.getInt("key"))
        }
    }
    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentFirstBinding.inflate(inflater, container, false)
        return binding.root

    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)


        binding.buttonFirst.setOnClickListener {
            // 스레드 실행
            if(timeCountThread==null) {
                timeCountThread = context?.let { it1 ->
                    TimeCountThread(
                        handler,
                        it1, binding.textviewFirst
                    )
                }
                timeCountThread?.start()
            }
//            findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
        }
        // 스레드 중지
        binding.buttonSecond.setOnClickListener {
            timeCountThread?.stopThread()
            timeCountThread=null
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

 

위 버튼을 누르면 시간이 흘러갑니다. 5초마다 갱신~!

아래 버튼을 누르면 멈춥니다.

반응형

댓글