๐ SeSAC์ 'JetPack๊ณผ Kotlin์ ํ์ฉํ Android App ๊ฐ๋ฐ' ๊ฐ์ข๋ฅผ ์ ๋ฆฌํ ๊ธ ์ ๋๋ค.
Activity Not Response ์ ์ฝ์ด. ์กํฐ๋นํฐ์์ ์ผ์ด๋๋ ์๋ฌ ์ํฉ์ ๋งํ๋ค.
์ ์ ์ด๋ฒคํธ์ ์กํฐ๋นํฐ๊ฐ 5์ด ์ด๋ด์ ๋ฐ์ํ์ง ๋ชปํ๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ ์๋ฌ
์ ์ ๊ฐ ์ด๋ฒคํธ๋ฅผ ๊ฐํ๋ฉด -> ์ด๋ฒคํธ๊ฐ ์ด๋ฒคํธ ํ์ ๋ด๊ธฐ๊ณ -> ์์คํ ์์ ์ด๋ฒคํธ ํ๋ฅผ ์๋์ผ๋ก ๊ฐ์ง -> ์ด๋ฒคํธ ํ์์ ์ด๋ฒคํธ ์ถ์ถ ํ ์ ๋ฌด ์งํ
โ ANR ๋ฌธ์ ๋ ์ด๋ฒคํธ ํ์ ์ด๋ฒคํธ๊ฐ ๋ด๊ธฐ๋ ์๊ฐ๋ถํฐ 5์ด ์ด๋ด์ ํด๋น ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ฐ ์งํ๋์ง ์์ผ๋ฉด ์์คํ ์์ ๊ฐ์ ์ ์ผ๋ก ์กํฐ๋นํฐ๋ฅผ ์ข ๋ฃ์ํค๋ ๊ฒ์ ๋งํ๋ค.
๊ทธ๋ฅ ๋คํธ์ํน
์ด ๋ค์ด๊ฐ๋ ์ฝ๋๋ ๋ฌด์กฐ๊ฑด ANR ๋ฌธ์ ๋ฅผ ๊ณ ๋ คํด์ผ๋ง ํ๋ค๊ณ ์ธ์ฐ์.
Thread
- Handler ๋ก ํด๊ฒฐ
AsyncTask
๋ก ํด๊ฒฐ
Coroutine
์ผ๋ก ํด๊ฒฐ
์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ํด๊ฒฐ ํ ์ ์๋ค. ํ์ง๋ง ์๋๋ก์ด๋ 11๋ฒ์ ์ผ๋ก ์ฌ๋ผ๋ฉด์ ์์ ๋ ๊ฐ๋ deprecated ๋๋ค. ํ์ฌ Coroutine
์ผ๋ก ๊ฐ๋ฐํ๋ ๊ฒ์ ๊ถ์ฅํ๊ณ ์๋ค.
onCreate ๋ถํฐ ์คํ์์ผ ํ๋ฉด์ ์ถ๋ ฅ ์ํค๊ณ ์ ์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ์ค๋ ๋๋ฅผ ๋ฉ์ธ ์ค๋ ๋
๋ผ๊ณ ํ๋ค. ๋๋ UI๋ฅผ ์ถ๋ ฅ ํ๋ค ํ์ฌ UI ์ค๋ ๋๋ผ ๋ถ๋ฅธ๋ค. ANR ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ๋ฉ์ธ ์ค๋ ๋์ ๋ณ๊ฐ๋ก ์
๋ฌด ๋ก์ง์ ์ฒ๋ฆฌํ ๊ฐ๋ฐ์ ์ค๋ ๋๊ฐ ํ์ํ๋ค. ๊ทธ๋์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์์
๋ค์ ์ค๋ ๋๋ฅผ ๋ฐ๋ก ๋์ถํด์ ์ฒ๋ฆฌํด ์ฃผ๋ฉด ๋๋ค.
๊ทธ๋ฐ๋ฐ ๊ฐ๋ฐ์ ์ค๋ ๋๋ก ํ๋ก๊ทธ๋จ์ ์ง๋ฉด ANR ๋ฌธ์ ๋ ํผํ ์ ์์ง๋ง ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค.
์กํฐ๋นํฐ ๋ด์์ ๋ฉ์ธ ์ค๋ ๋์ ๊ฐ๋ฐ์ ์ค๋ ๋๊ฐ ๋์ํ๊ณ ์๋ค. ๊ทธ ์์ค์ ๊ฐ๋ฐ์ ์ค๋ ๋๊ฐ ํ๋ฉด ์ถ๋ ฅ ์์์ธ View ์ ์ ๊ทผ์ ํ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. ์ฆ, ๊ฐ๋ฐ์ ์ค๋ ๋ ๋ด์์ ํ๋ฉด ์ถ๋ ฅ ์์์ธ View ์ ์ ๊ทผ์ด ๋ถ๊ฐ๋ฅํ๊ฒ ํ๋ก๊ทธ๋จ์ ์์ฑํด์ผ ํ๋ค. ๋ฉ์ธ ์ค๋ ๋์ ์ํด์๋ง View ๊ฐ ๊ด๋ฆฌ๋์ด์ผ๋ง ํ๋ค.
๊ทธ๋ฐ๋ฐ ์ดํ๋ฆฌ์ผ์ด์ ํน์ฑ ์ ํ๋ฉด ์ถ๋ ฅ์ด ์ ๋ฌด์ ์ํ์ด์ ์ค๋ฉ๊ฐ์ด๋ค. ๊ฐ๋ฐ์ ์ค๋ ๋์์ ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ๋์ด์๋, ๊ฒฐ๊ตญ ๊ทธ๊ฑธ ํ๋ฉด์ ๋์์ผ ์๋ฏธ๊ฐ ์๋ค. ๊ทธ๋ผ ์ด๋ป๊ฒ ํด์ผ ํ ๊น?
๐ Handler
๋ฅผ ์ฌ์ฉํ๋ค. ๋ง์ฝ ํ๋ฉด์ ๊ตฌ์ฑํ๋ View ๋ฅผ ์ด์ฉํด์ผ ํ๋ค๋ฉด, ์ง์ ์ ๊ทผํ์ง ๋ง๊ณ Handler ํด๋์ค
๋ฅผ ์ฌ์ฉํ๋ค. ๊ทธ๋ฆฌ๊ณ Handler ํด๋์ค
๋ ๋ฉ์ธ ์ค๋ ๋์๊ฒ ์
๋ฌด๋ฅผ ์๋ขฐํ๋ ๊ฒ์ผ๋ก, ๋ฉ์ธ ์ค๋ ๋์ ์ํด์๋ง View๊ฐ ๊ด๋ฆฌ ๋๊ฒ๋ ํ๋ค.
์ด๊ฒ์ ํํ ์ค๋ ๋-ํธ๋ค๋ฌ ๊ตฌ์กฐ
๋ผ๊ณ ํ๋ค. ๋ฉํฐ ์ค๋ ๋ ํ๊ฒฝ์ผ๋ก ๊ฐ๋ฐ ์์ ์ฐ๋ ๋ ๊ฐ์ ์ญํ ๋ถ๋ด์ ์๋ฒฝํ ๋ถ๋ฆฌํ๋ ๊ฒ์ผ๋ก, ํ๋ฉด์ ๊ด๋ฆฌํ๋ ์ค๋ ๋์ ์
๋ฌด๋ก์ง์ ์ํํ๋ ์ค๋ ๋๋ฅผ ๋๋๋ค.
Handler ๋ก main thread ์๊ฒ ์์ ์๋ขฐ
sendMessage(Message msg)
: ๋งค๊ฐ๋ณ์๋ก ๋ฉ์ธ ์ค๋ ๋์๊ฒ ์ ๋ฌํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ๋ฉ์์ง ๊ฐ์ฒด๋ฅผ ๋ฐ๋๋ค.
sendMessageAtFrontOfQueue(Message msg)
: View ์์
์ ๋ํ ์๋ขฐ๊ฐ ๋ฐ๋ณต์ ์ผ๋ก ๋ฐ์ํ ๊ฒฝ์ฐ UI Thread์์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํ๋๋ฐ ์ด๋ฒ ์๋ขฐ๋ฅผ ๊ฐ์ฅ ๋จผ์ ์ฒ๋ฆฌํ๋ผ๋ ์์ฒญ
sendMessageAtTime(Message msg, long uptimeMillis)
: ์๋ขฐ๋ฅผ ์ง์ ๋ ์๊ฐ์ ์ํ
sendMessageDelayed(Message msg, long delayMillis)
: ์ง์ฐ์๊ฐ ํ์ ์ํ ์์ผ ๋ฌ๋ผ๋ ์์ฒญ
sendEmptyMessage(int what)
: ๋ฐ์ดํฐ ์ ๋ฌ ์์ด ์๋ขฐํ๋ ๊ฒฝ์ฐ
Message ๊ฐ์ฒด๋ main thread ์๊ฒ ๋๊ธฐ๋ ๋ฐ์ดํฐ
what
: int ํ ๋ณ์๋ก ๊ตฌ๋ถ์. ๊ฐ๋ฐ์๊ฐ ์์ ์ซ์๊ฐ์ผ๋ก ์์ฒญ์ ๊ตฌ๋ถํ๊ธฐ ์ํด์ ์ฌ์ฉ.
obj
: UI Thread ์๊ฒ ๋๊ธธ ๋ฐ์ดํฐ. Object ํ์
์ ๋ณ์.
arg1, arg2
: UI Thread ์๊ฒ ๋๊ธธ ๋ฐ์ดํฐ. int ํ์
์ผ๋ก ๊ฐ๋จํ ์ซ์๊ฐ์ arg1, arg2 ๋ณ์์ ๋ด์ ์ ๋ฌ.
์ซ์๊ฐ ๋๊ธฐ๊ธฐ ๋ฑ์ ๊ฐ๋จํ ์์
๊ฐ์ ๊ฒฝ์ฐ์๋ obj
๊ฐ ์๋ arg1, arg2
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
var message = Message() // ๋ฉ์์ง ์ค๋น
message.what = 1 // ์๋ณ์
message.arg1 = count // ๋๊ธฐ๋ ๋ฐ์ดํฐ
handler.sendMessage(message) // ํธ๋ค๋ฌ ๊ฐ์ฒด์ ๋ฉ์๋ ์ฝ
var handler: Handler = object : Handler() { // Handler ํด๋์ค ์์
override fun handleMessage(msg: Message) { // handleMessage ํจ์ ์ค๋ฒ๋ผ์ด๋
if (msg.what === 1) {
textView.setText(String.valueOf(msg.arg1))
} else if (msg.what === 2) {
textView.text = msg.obj as String
}
}
}
์ ์ ์ด๋ฒคํธ๋ฅผ ๋ฐ์๋ค์ด๋ ๋ฉ์ธ ์ค๋ ๋์ ์นด์ดํธ ๋ค์ด ๋ก์ง์ ์ํํ๋ ๊ฐ๋ฐ์ ์ค๋ ๋๋ก ๋ถ๋ฆฌ ํด๋ณด์.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#1a237e">
<TextView
android:id="@+id/main_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="10"
android:textSize="80dp"
android:textStyle="bold"
android:textColor="@android:color/white"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="16dp">
<ImageView
android:id="@+id/main_startBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_start"
android:clickable="true"/>
<ImageView
android:id="@+id/main_pauseBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_pause"
android:clickable="true"/>
</LinearLayout>
</RelativeLayout>
package com.kotdev99.android.c47
class MainActivity : AppCompatActivity() {
private lateinit var startView: ImageView
private lateinit var pauseView: ImageView
private lateinit var textView: TextView
// ์ค๋ ๋ ์ ์ด boolean
private var loopFlag = true
private var isFirst = true
private var isRun = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startView = findViewById(R.id.main_startBtn)
pauseView = findViewById(R.id.main_pauseBtn)
textView = findViewById(R.id.main_textView)
startView.setOnClickListener {
if (isFirst) {
isFirst = false
isRun = true
thread.start()
} else {
isRun = true
}
}
pauseView.setOnClickListener {
isRun = false
}
}
var handler: Handler = object : Handler() {
override fun handleMessage(msg: Message) {
if (msg.what === 1) {
textView.setText(String.valueOf(msg.arg1))
} else if (msg.what === 2) {
textView.text = msg.obj as String
}
}
}
var thread: Thread = object : Thread() {
override fun run() {
try {
var count = 10
while (loopFlag) {
sleep(1000)
if (isRun) {
count--
var message = Message()
message.what = 1
message.arg1 = count
handler.sendMessage(message)
if (count == 0) {
message = Message()
message.what = 2
message.obj = "Finish!!"
handler.sendMessage(message)
loopFlag = false
}
}
}
} catch (e: Exception) {
}
}
}
}
ANR ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ ๋ฐฉ๋ฒ ์ค ํ๋. deprecation ๋์์ง๋ง ์ฌ์ ํ ๋ง์ด ์ฌ์ฉ๋๊ณ ์๋ค.
Thread - Handler ๊ตฌ์กฐ๋ฅผ ์ถ์ํํ์ฌ ์ข ๋ ์ฝ๊ฒ ๊ฐ๋ฐํ ์ ์๊ฒ๋ ๋ง๋ค์๋ค.
AsyncTask ๋ฅผ ์์๋ฐ์ ์์ฑํ๋ค.
class MyAsyncTask: AsyncTask<Void?, Int?, String>() {
//..............
}
doInBackground(Params... params)
Thread์ ์ํด ์ฒ๋ฆฌ๋ ๋ด์ฉ์ ๋ด๊ธฐ ์ํ ํจ์. ๋ฐ๋์ ์ค๋ฒ๋ฆฌ์๋ํด์ผ ํ๋ค.
onPreExecute()
AsyncTask์ ์์
์ ์์ํ๊ธฐ ์ ์ ํธ์ถ. AsyncTask์์ ๊ฐ์ฅ ๋จผ์ ํ ๋ฒ ํธ์ถ.
onPostExecute(Result result)
AsyncTask์ ๋ชจ๋ ์์
์ด ์๋ฃ๋ ํ ๊ฐ์ฅ ๋ง์ง๋ง์ ํ ๋ฒ ํธ์ถ. doInBackground ํจ์์ ์ต์ข
๊ฐ์ ๋ฐ๊ธฐ ์ํด ์ฌ์ฉ.
onProgressUpdate(Progress... values)
doInBackground์ ์ํด ์ฒ๋ฆฌ๋๋ ์ค๊ฐ์ค๊ฐ ๊ฐ์ ๋ฐ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด์ ํธ์ถ. doInBackground์์ publishProgress ํจ์๋ก ๋๊ธด ๊ฐ์ด ์ ๋ฌ.
์ ๋ฌด ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ์ ๋ฐ์ดํฐ ํ์ ์ ์ ๋ค๋ฆญ์ผ๋ก ์ ์ธํด์ผ ํ๋ค. ๊ทธ๋์ AsyncTask๋ฅผ ์์๋ฐ์ ๋ ์ ๋ค๋ฆญ์ผ๋ก 3๊ฐ์ ํ์ ์ ์ง์ ํด ์ค์ผ ํ๋ค.
class MyAsyncTask: AsyncTask<Void?, Int?, String>()
์ฒซ ๋ฒ์งธ ํ์ : Background ์์ ์ ์ํ doInBackground ์ ๋งค๊ฐ๋ณ์ ํ์ ๊ณผ ๋์ผ. AsyncTask ์ ์ํด Background ์์ ์ ์๋ขฐํ ๋ ๋๊ธธ ๋ฐ์ดํฐ์ ํ์ . ์์ผ๋ฉด Void ๋ก ์ง์ .
๋ ๋ฒ์งธ ํ์ : doInBackground ํจ์ ์ํ์ ์ํด ๋ฐ์ํ ๋ฐ์ดํฐ๋ฅผ publishProgress() ํจ์๋ฅผ ์ด์ฉํด ์ ๋ฌํ๋๋ฐ, ์ด ๋์ ์ ๋ฌ ๋ฐ์ดํฐ ํ์ . ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ ๋ฐ์ onProgressUpdate ํจ์์ ๋งค๊ฐ๋ณ์์ ํ์ ๊ณผ ๋์ผํ๊ฒ ์ง์ .
์ธ ๋ฒ์งธ ํ์ : onPostExecute ์ ๋งค๊ฐ๋ณ์ ํ์ ๊ณผ ๋์ผํ๊ฒ ์ง์ . doInBackground ํจ์์ ๋ฆฌํด ํ์ ์ด๋ฉฐ ๋ฆฌํด๋ ๋ฐ์ดํฐ๊ฐ onPostExecute ํจ์์ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌ๋จ.
์ฆ <doInBackground ์ ๋งค๊ฐ๋ณ์ , onProgressUpdate ์ ๋งค๊ฐ๋ณ์ , onPostExecute ์ ๋งค๊ฐ๋ณ์>
์ ์ค์ต๊ณผ ๋์ผ
package com.kotdev99.android.c48
class MainActivity : AppCompatActivity() {
lateinit var startView: ImageView
lateinit var pauseView: ImageView
lateinit var textView: TextView
var isFirst = true
lateinit var asyncTask: MyAsyncTask
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startView = findViewById(R.id.main_startBtn)
pauseView = findViewById(R.id.main_pauseBtn)
textView = findViewById(R.id.main_textView)
startView.setOnClickListener {
if (isFirst) {
asyncTask.isRun = true
asyncTask.execute() // execute ํจ์๋ฅผ ํธ์ถํ๋ ์๊ฐ doInBackground ํจ์ ์คํ
isFirst = false
} else {
asyncTask.isRun = true
}
}
pauseView.setOnClickListener {
asyncTask.isRun = false
}
asyncTask = MyAsyncTask()
}
inner class MyAsyncTask : AsyncTask<Void?, Int?, String>() {
var loopFlag = true
var isRun = false
override fun doInBackground(vararg p0: Void?): String {
var count = 10
while (loopFlag) {
SystemClock.sleep(1000)
if (isRun) {
count--
publishProgress(count)
if (count == 0) {
loopFlag = false
}
}
}
return "Finish!!"
}
// ์ด ํจ์๋ ๋ฉ์ธ ์ค๋ ๋์ ์ํด์ ํธ์ถ๋จ. ์ฆ, ๋ทฐ ๊ฐ์ฒด๋ฅผ ์ด์ฉํ ์ ์์.
// doInBackground ํจ์์์ publishProgress ๊ฐ ์ฝ ๋์์ ๋ ํธ์ถ ๋๋ค.
override fun onProgressUpdate(vararg values: Int?) {
super.onProgressUpdate(*values)
textView.setText(values[0].toString())
}
// doInBackground ํจ์๊ฐ ์ต์ข
์ข
๋ฃ๋ ์๊ฐ์ ๋ง์ง๋ง ๋ฆฌํด ๊ฐ์ ๋ฐ์์ ํธ์ถ ๋๋ค.
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
textView.setText(result)
}
}
}
์ฝ๋ฃจํด์ ๊ฒฝ์ฐ ๋ ์ ๊ฐ์ ์ฝ์ค๊ฐ ๋ง๋ค์ด์ง ์ ๋๋ก ๋นก์ธ๋ค. ์ฌ๊ธฐ์๋ ANR ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์ ๋๋ก๋ง ๋ค๋ฃฌ๋ค.
ํํ Non-Blocking lightweight thread ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
๊ตฌ๊ธ ๊ณต์ ๋ฌธ์์ ์ ํ์๋ ์ฅ์ ์ ์๋์ ๊ฐ๋ค.
๊ฒฝ๋์ด๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ์ ๋ค.
์ทจ์ ๋ฑ ๋ค์ํ ๊ธฐ๋ฒ์ ์ง์ํ๋ค.
๋ง์ JetPack ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์ฉ๋์ด ์๋ค.
์ค๋ ๋๋ ์๋์ง๋ง ์ค๋ ๋์ ๋์ผํ๊ฒ ๋ฉ์ธ ์ค๋ ๋์๋ ๋ณ๊ฐ๋ก ์์ ์ํ์ด ๊ฐ๋ฅํ๋ค.
์ฌ์ฉํ๋ ค๋ฉด ์์กด์ฑ์ ์ถ๊ฐํด์ผ ํ๋ค.
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
์ฝ๋ฃจํด ์์
์ ํ๊ธฐ ์ํด์๋ ์ฐ์ ์ค์ฝํ
๋ผ๋ ๊ฒ ํ์ํ๋ค.
์ค์ฝํ : ์ฝ๋ฃจํด์ด ์คํ๋๋ ์์ญ
CoroutineScope ์ ๊ตฌํ ํด๋์ค
GlobalScope, ActorScope, ProducerScope ๋ฑ ์ ๊ณต
val backgroundScope = CoroutineScope(Dispatchers.Default + Job())
์ฝ๋ฃจํด์ ๊ตฌ๋์ํฌ ๋ ์ด ์ฝ๋ฃจํด์ ์ด๋ค ์ค๋ ๋๊ฐ ๋งก์ ๊ฒ์ธ๊ฐ๋ฅผ ์ง์
Dispatchers.Main : ์กํฐ๋นํฐ์ ๋ฉ์ธ ์ค๋ ๋์์ ๋์ํ๋ ์ฝ๋ฃจํด์ ๋ง๋ค๊ธฐ ์ํ ๋์คํจ์ฒ. ๋ทฐ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ์ ์๋ ์ ์ผํ ๋์คํจ์ฒ. UI ๊ด๋ จ ์์ ์ ๋ฌด์กฐ๊ฑด ์ด๊ณณ์์ ์ฒ๋ฆฌ ๋์ด์ผ๋ง ํ๋ค.
Dispatchers.IO : ํ์ผ์ ์ฝ๊ธฐ ํน์ ์ฐ๊ธฐ ๋๋ ๋คํธ์ํฌ ์์ ๋ฑ์ ์ต์ ํ๋ ๋์คํจ์ฒ
Dispatchers.Default : CPU๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ ์์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํํ ๋ชฉ์ ์ ๋์คํจ์ฒ
Scope
์ Dispatcher
๋ฅผ ์ง์ ํด์ ์ฝ๋ฃจํด์ ๊ตฌ๋์ํค๋ฉด, ์ฝ๋ฃจํด ์ด Dispatcher
์ ์ํด์ ์คํ์ด ๋๋ค.
Coroutine ์ launch, async ๋ฑ์ ํจ์์ ์ํด ์คํ
launch, async ๋ Coroutine Builder ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
backgroundScope.launch {
//.........
}
CLICK ๋ฒํผ์ ๋๋ฅด๋ฉด ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์ฐ์ฐ ์์ ์ ์ํ.
๊ทธ ์์ค์ EditText์ ์ ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ANR ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ์ด๊ฒ์ ์ฝ๋ฃจํด์ผ๋ก ํด๊ฒฐ ํด๋ณด์.
<?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:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click" />
<TextView
android:id="@+id/resultView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:textStyle="bold" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
package com.kotdev99.android.c49
class MainActivity : AppCompatActivity() {
// ๊ต์ฅํ ํฐ ์ฐ์ฐ ์์
์ ์ํ ํ๋ ์ฝ๋ฃจํด
val backgroundScope = CoroutineScope(Dispatchers.Default + Job())
lateinit var button: Button
lateinit var resultView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button = findViewById(R.id.button)
resultView = findViewById(R.id.resultView)
button.setOnClickListener {
backgroundScope.launch {
var sum = 0L
var time = measureTimeMillis {
for (i in 1..2_000_000_000) {
sum += i
}
}
// Dispatchers.Main ์๊ฒ ๊ฒฐ๊ณผ ๊ฐ์ ํ๋ฉด์ ์ฐ์ด ๋ฌ๋ผ๊ณ ์๋ขฐ
withContext(Dispatchers.Main) {
resultView.text = "sum : $sum"
}
}
}
}
}