[Android] Coroutine practice

델버·2022년 6월 12일
1

Android

목록 보기
4/5

코틀린, 코트린,코ㅌ리…..코루틴!

코루틴의 개념은 공부했지만 왜 쓰는지 모르는 동무들을 위해 간단하게 예시를 만들어봤다.


코루틴 적용 전

  • 버튼을 누르면 execute()가 돌아가 Log를 찍는다. 하지만 얼마 가지 않아 강제 종료를 맛 볼 것이다.
  • 이유: android에서 작업이 돌아가면 UI가 사용자와의 상호작용을 멈추게 된다. 이때 5초 정도 지속되면 android에서는 강제 종료하는 창을 띄우게 된다.
  • 해결: 코루틴을 사용하면 이 작업을 다른 thread로 넘겨버린다. 그래서 UI는 멈추지 않고, android는 사용자와 상호작용을 하면서 작업은 다른 thread에서 계속하게 된다.
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val btn_start : Button = findViewById(R.id.btn_start)
        btn_start.setOnClickListener{
            execute("작업 완료")
        }
    }
    private fun execute(result: String) {
        for(i in 1..100000) {
            Log.e("delay : ", ""+i)
        }
        Toast.makeText(
            this, "Done",
            Toast.LENGTH_SHORT
        ).show()
    }
}

코틀린 적용 !

1. dependence 의존성 추가

  • implementation "androidx.activity:activity-ktx:1.4.0"

2. 작업 함수 수정

  1. suspend 키워드 추가
  2. 다른 thread에서도 execute가 실행되는지 확인
  3. withContext(Dispatchers.IO){} 에 넣기 - IO thread로 작업을 넘긴다
  4. scope 지정
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val btn_start : Button = findViewById(R.id.btn_start)
        btn_start.setOnClickListener{
            lifecycleScope.launch{
						// 4. scope 지정
                execute("작업 완료")
            }

        }
    }

private suspend fun execute(result: String) {
				// 1. suspend 추가 
				// 2. execute가 다른 곳에서도 사용하는지 확인
        withContext(Dispatchers.IO){
            // 3. withContext 작업을 IO 쓰레드로 이동시킴
            for(i in 1..100000) {
                Log.e("delay : ", ""+i)
            }
            Toast.makeText(
                this@MainActivity, result,
                Toast.LENGTH_SHORT
            ).show()
        }
}

3. 강제종료..(UI thread)

  • 하지만 강제종료..Toast는 UI thread에서만 돌아가지만 이 coroutine은 IO thread에서 돌아가기 때문이다.
  • 그래서 runOnUiThread 를 사용해 UI thread로 실행시킨다. 그럼 실행 완료!
private suspend fun execute(result: String) {
        withContext(Dispatchers.IO){
            // withContext 작업을 IO thread로 이동시킴
            for(i in 1..100000) {
                Log.e("delay : ", ""+i)
            }
            runOnUiThread{
                Toast.makeText(
								// UI Thread로 작업을 넘긴다. 
                    this@MainActivity, result,
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }

번외 - Please wait dialog 만들기

  • 앱이 작업하는 동안 사용자가 지루하지 않게 please wait가 적힌 동글뱅이를 돌리는 화면을 보여준다
  • 작업이 끝나면 사라지게 만들면 끝!

var customProgressDialog: Dialog? = null

private fun cancelProgressDialog() {
    if (customProgressDialog != null) {
        customProgressDialog?.dismiss()
        customProgressDialog = null
    }
}

private fun showProgressDialog() {
    customProgressDialog = Dialog(this)
    customProgressDialog?.setContentView(R.layout.dialog_custom_progress)
    customProgressDialog?.show()
}
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val btn_start : Button = findViewById(R.id.btn_start)
        btn_start.setOnClickListener{
            showProgressDialog()
					// dialog를 보여준다.
            lifecycleScope.launch{
                execute("작업 완료")
            }

        }
    }

    private suspend fun execute(result: String) {
        withContext(Dispatchers.IO){
            // withContext 작업을 다른 쓰레드로 이동시킴
            for(i in 1..1000000) {
                Log.e("delay : ", ""+i)
            }
            runOnUiThread{
                cancelProgressDialog()
							// 작업이 끝나면 dialog를 사라지게하고 완료 메세지를 보여준다.
                Toast.makeText(
                    this@MainActivity, result,
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }

완성

0개의 댓글