반응형

Thread & Handler

설명

  • 비동기 처리를 위해 Thread를 사용한다.
  • Activity 처리를 위한 Thread를 Main Thread, UI Thread라고 부른다.
  • 네트워크 관련 코드는 전부 Main Thread가 아닌 새로 Thread를 생성해서 처리해야한다.
  • 안드로이드 오레오(8.0) 이상에서는 개발자가 발생시킨 Thread에서 화면 처리가 가능하다.
  • 그 이전 버전에서는 Handler를 통해 처리해야한다.
  • Handler는 Main Thread에서 처리가 필요한 작업을 수행한다. (5초 이상 걸리는 작업 불가)

기본 코드

res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="" />

</LinearLayout>
MainActivity
class MainActivity : AppCompatActivity() {
    private val handler = Handler()
    private var isRunning = false
    private var textView: TextView? = null

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

        textView = findViewById(R.id.textView)

        isRunning = true
        TimerThread().start()
    }

    override fun onDestroy() {
        super.onDestroy()
        isRunning = false
    }

    inner class TimerThread : Thread() {
        override fun run() {
            while (isRunning) {
                SystemClock.sleep(100)

                handler.post { textView?.text = System.currentTimeMillis().toString() }
            }
        }
    }
}

sendMessage 활용 코드

MainActivity
class MainActivity : AppCompatActivity() {
    private val handler = DisplayHandler()
    private var isRunning = false
    private var textView: TextView? = null

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

        textView = findViewById(R.id.textView)

        isRunning = true
        TimerThread().start()
    }

    override fun onDestroy() {
        super.onDestroy()
        isRunning = false
    }

    inner class TimerThread : Thread() {
        override fun run() {
            while (isRunning) {
                SystemClock.sleep(100)

                val message = Message()
                message.what = 0
                message.obj = System.currentTimeMillis()

                handler.sendMessage(message)
            }
        }
    }

    inner class DisplayHandler : Handler() {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)

            textView?.text = msg.obj.toString()
        }
    }
}

참고

AsyncTask

설명

  • 비동기 처리를 위해 제공되는 클래스
  • Thread + Handler

코드

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

        val sync = MyAsyncTask()
        sync.execute(10, 20)
    }

    inner class MyAsyncTask : AsyncTask<Int, Long, String>() {
        // doInBackground 호출 전 호출되는 메서드, Main Thread가 처리한다.
        override fun onPreExecute() {
            super.onPreExecute()
            Toast.makeText(baseContext, "onPreExecute", Toast.LENGTH_SHORT).show()
        }

        // 일반 Thread에서 처리한다.
        override fun doInBackground(vararg params: Int?): String {
            var a1 = params[0]!! // nullable을 not nullable로 변환을 위해 !! 키워드 추가
            var a2 = params[1]!!

            for (index in 0..3) {
                SystemClock.sleep(5000)
                a1++
                a2++

                val time = System.currentTimeMillis()
                publishProgress(time) // onProgressUpdate() 호출
            }

            return "수행이 완료되었습니다."
        }

        // Main Thread에서 수행할 작업 처리
        override fun onProgressUpdate(vararg values: Long?) {
            super.onProgressUpdate(*values)

            Toast.makeText(baseContext, "onProgressUpdate - ${values[0]}", Toast.LENGTH_SHORT).show()
        }

        // doInBackground 종료시 실행
        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)

            Toast.makeText(baseContext, "onPostExecute - ${result}", Toast.LENGTH_SHORT).show()
        }
    }
}

참고

RunOnUiThread

설명

  • 개발자가 발생시킨 일반 쓰래드에서 코드 일부를 Main Thread가 처리하도록 하는 메서드

코드

MainActivity
class MainActivity : AppCompatActivity() {
    private var isRunning = false

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

        isRunning = true

        val thread = MyThread()
        thread.start()
    }

    override fun onDestroy() {
        super.onDestroy()
        isRunning = false
    }

    inner class MyThread: Thread() {
        override fun run() {
            while (isRunning) {
                SystemClock.sleep(1000)

                runOnUiThread {
                    Toast.makeText(baseContext, System.currentTimeMillis().toString(), Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
}

참고

반응형

'Development > Android' 카테고리의 다른 글

[Android] Service  (0) 2021.02.09
[Android] BroadcastReceiver  (0) 2021.02.09
[Android] DialogFragment  (0) 2021.02.09
[Android] ListFragment  (0) 2021.02.09
[Android] Fragment  (0) 2021.02.09

+ Recent posts