안드로이드 공부/ Async

yellow·2021년 6월 5일
0

안드로이드 공부

목록 보기
25/28

동기 vs. 비동기

매우 오래 걸리는 작업을 해야하는 상황이라고 가정하자.

📎 동기 (Sync)

작업을 순차적으로 진행한다.
따라서 해당 작업이 끝나기 전까지는 다른 작업을 수행할 수 없다.

📎 비동기 (Async)

Thread를 만들어서 매우 오래 걸리는 작업을 Thread가 따로 처리하도록 한다.
따라서 그동안 Main Thread는 다른 작업을 수행할 수 있다.


AsyncTask

안드로이드에서 Async를 다루는 방법이다.

현재는 AsyncTask가 deprecated 되었고, rxJava나 coroutine 등으로 대체할 수 있다고 한다. 이에 대한 내용은 따로 블로그를 작성하여 올릴 예정이다.

  • 작업 시간이 길어서 Main Thread를 방해하는 경우에 사용된다.
  • background로 진행되면서 작업이 끝나면 Main Thread로 결과를 return 해준다.
  • UI Thread의 작업도 해야하는 경우에 사용한다.
  • 네트워크, DB 쿼리 등을 할 때 사용된다.

단점

  • 재사용이 불가능하다.
  • 구현된 Activity가 종료된다고 같이 종료되지 않는다. 따라서 Activity 생명주기에 따라 적당한 메소드(ex. onPause())에 task를 종료하는 코드를 넣어야 한다.
  • 병렬 처리가 안된다. (AsyncTask는 하나만 실행될 수 있다.)

📎 AsyncTask 사용하기

1. AsyncTask를 상속받는 class 작성하기

class BackgroundAsyncTask(): AsyncTask<Params, Progress, Result>(){

}
  • Params : doInBackground의 파라미터 타입
  • Progress : onProgressUpdate의 파라미터 타입
  • Result : onPostExecute의 파라미터 타입

2. 메소드 오버라이딩 하기

  • onPreExecute() : 백그라운드 작업이 시작되기 전에 해야하는 작업. 주로 초기화 작업 수행
  • doInBackground() : 백그라운드에서 해야하는 작업 (execute())
  • onProgressUpdate() : 백그라운드 작업을 하면서 중간 중간 MainThread에 접근해야 하는 경우에 사용
  • onPostExecute() : 백그라운드 작업이 끝나면 호출됨. 주로 메모리 자원 해제 등의 작업 수행
  • onCancelled() : task가 인위적으로 취소되었을 때 호출됨.(cancel())

onPreExecute(), onProgressUpdate(), onPostUpdate()는 MainThread에서 수행되기 때문에 UI 객체에 접근할 수 있다.

3. AsyncTask 실행하고 중단하기

  • execute() : 백그라운드 작업 수행 시작
  • cancel() : 백그라운드 작업 취소

예제 코드

package com.example.myapplication

import android.os.AsyncTask
import android.os.Bundle
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

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

        val startButton : Button = findViewById(R.id.button_start)
        val stopButton : Button = findViewById(R.id.button_stop)
        val progressBar : ProgressBar = findViewById(R.id.progress_bar)
        val progressText : TextView = findViewById(R.id.ment)

        var task : BackgroundAsyncTask? = null

        startButton.setOnClickListener {
            task = BackgroundAsyncTask(progressBar, progressText)
            task?.execute()
        }

        stopButton.setOnClickListener {
            task?.cancel(true)
        }
    }
}

// AsyncTask 만들기
class BackgroundAsyncTask(
    val progressBar : ProgressBar,
    val progressText: TextView
): AsyncTask<Int, Int, Int>(){

    var percent: Int = 0

    override fun onPreExecute() {
        percent = 0 // 처음에는 percent가 무조건 0이어야 한다.
        progressBar.progress = percent // progressBar 갱신
    }

    // thread가 할 작업
    override fun doInBackground(vararg params: Int?): Int {
        while(isCancelled() == false){
            percent++
            if(percent>100){
                break
            }else{
                publishProgress(percent) // 이게 실행되면 onProgressUpdate에 percent가 넘어간다
            }
            try{
                Thread.sleep(100) // 0.1초 delay
            }catch (e : Exception){
                e.printStackTrace()
            }
        }
        return percent // 100퍼센트가 되면 percent 리턴
    }

    override fun onProgressUpdate(vararg values: Int?) {
        progressBar.progress = values[0] ?: 0 // progress 값 갱신
        progressText.text = "퍼센트 : " + values[0]
        super.onProgressUpdate(*values)
    }

    override fun onPostExecute(result: Int?) {
        progressText.text = "작업이 완료되었습니다."
    }

    override fun onCancelled(result: Int?) {
        super.onCancelled(result)
    }

    // task가 인위적으로 취소되었을 때
    override fun onCancelled() {
        progressBar.progress = 0
        progressText.text = "작업이 취소되었습니다."
    }
}
  • 실행 결과
profile
할 수 있어! :)

0개의 댓글