Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

기록장

[안드로이드] AsyncTask 이해 및 간단한 예제 본문

안드로이드

[안드로이드] AsyncTask 이해 및 간단한 예제

edit0 2021. 1. 7. 18:26

전에 했던 스레드 관련 포스팅을 보셨다면 스레드 사용에 있어서 핸들러를 사용하든지 Runnable 객체를 사용하는 방법을 보셨을 것이다. 이 작업을 좀 더 간단하게 구현할 수 있도록 지원하는 AsyncTask 클래스에 대해 포스팅 해보도록 하겠다.

 

AsyncTask 클래스는 쓰레드 작업을 할 때 사용되는 클래스이다. 표준 Thread와 Runnable 객체를 사용하면 따로따로 구현하고 호출해주어야 하는데, 이 클래스를 상속하여 사용하면 그 안에 쓰레드 구현 코드와 UI 접근 코드를 한번에 구현할 수 있다.

 

그럼 AsyncTask에 대한 구조를 보도록 하겠다.

 

간단히 말하면 onPreExcuted() -> doInBackground() -> onPostExcuted() 순으로 진행된다.

doInBackground()에서 UI 접근이 필요할 경우 onProgressUpdate()를 호출하여 사용할 수 있는 구조이다.

execute로 실행한 다음은 AsyncTask 내부에서 필요한 경우마다 콜백 메소드들이 자동으로 호출된다.

이 정도만 알고 그림을 보면 어느정도 어떻게 돌아가는지 이해되실 것이다.

 

대표적인 메소드 4가지

  • onPreExecute(): 백그라운드 작업을 수행하기 전에 호출, 메인 스레드에서 실행되며 초기화 작업에 사용됨
  • doInBackground(): 새로 만든 스레드에서 백그라운드 작업을 수행(새 스레드에서 실행될 코드), execute() 메소드를 호출할 때 사용된 파라미터를 배열로 전달받음
  • onPostExecute(): 백그라운드 작업이 끝난 후에 호출, 메인 스레드에서 실행되며 메모리 리소스를 해제하는 등의 작업에 사용, 백그라운드 작업의 결과는 Result 타입의 파라미터로 전달
  • onProgressUpdate(): 백그라운드 작업의 진행 상태를 표시하기 위해 호출, 작업 중간 중간에 UI 객체에 접근하는 경우에 사용(메인 스레드에서 실행), 호출하기 위해서는 publishProgress() 메소드 호출

AsyncTask를 상속할 때는 <첫째, 둘째, 셋째> 기호 안에 3가지 타입을 정의하는데 첫번째는 doInBackground() 메소드의 파라미터, 두번째는 onProgressUpdate() 메소드의 파라미터, 세번째는 onPostExecute() 메소드의 파라미터를 나타낸다. 

 

execute() 메소드로 실행을 했으면 cancel() 메소드로 작업을 취소할 수 있는데 이 메소드를 호출하면 onCancelled() 메소드가 호출된다. 그리고 작업의 진행 상황을 확인하고 싶을 때는 getStatus() 메소드를 호출하면 되는데 반환은 PENDING, RUNNING, FINISHED 로 구분된다. (순서대로 시작전, 수행중, 종료)

 

주의사항

1. 객체 재사용이 불가능하다.

2. 기본 처리 작업 수 1개

 

코드

 

activity_main.xml

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

    <ProgressBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/progreesbar1"
        android:layout_marginBottom="50dp"
        style="?android:attr/progressBarStyleHorizontal"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/button1"
            android:text="시작"
            android:layout_marginRight="10dp"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/button2"
            android:text="취소"
            android:layout_marginLeft="10dp"/>
    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:id="@+id/textview1"
        android:textSize="30dp"/>


</LinearLayout>

 

MainActivity.java

public class MainActivity extends AppCompatActivity {

    asyntask_class asyntaskClass;
    Button b1,b2;
    ProgressBar pb1;
    TextView tv1;
    int value = 0;

    Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        b1 = findViewById(R.id.button1);
        b2 = findViewById(R.id.button2);
        pb1 = findViewById(R.id.progreesbar1);
        tv1 = findViewById(R.id.textview1);

        b1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                asyntaskClass = new asyntask_class();
                tv1.setText("");
                asyntaskClass.execute("전달받은 문자열"); //AsyncTask 호출
                //보낼 테이터가 없다면 asyntaskClass.execute() 로 호출하면 된다.
            }
        });

        b2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                asyntaskClass.cancel(true); //종료
            }
        });

    }

	// < > 기호 안 타입에 주의
    class asyntask_class extends AsyncTask<String, String, Integer>{

        //실행 시 첫번째로 실행
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            value = 0;
            pb1.setProgress(value);
            
            tv1.setText("onPreExecute()");

        }

        //새로 만들어진 스레드 작업 시작
        @Override
        protected Integer doInBackground(String... str) { //...은 가변길이 파라미터
            final String givenString = str[0]; //실행할 때 함께 보냈던 문자열

            //메인 스레드가 아니여서 UI에 접근을 못함, 그래서 핸들러 사용
            handler.post(new Runnable() {
                @Override
                public void run() {
                    tv1.setText(tv1.getText() + "\ndoInBackground()");
                    Toast.makeText(getApplicationContext(), givenString, Toast.LENGTH_SHORT).show();
                }
            });

            while(isCancelled() == false){
                value++;

                if(value >= 100){
                    break;
                }
                else {
                    String temp = String.valueOf(value);
                    publishProgress(temp); //onProgressUpdate 메소드가 String 타입이므로 변환해서 호출
                }

                try{
                    Thread.sleep(100);
                }catch (Exception e){

                }
            }

            return value; //onPostExecute()로 리턴
        }

        //doInBackground() 메소드 작업이 끝났을 경우 자동 호출
        @Override
        protected void onPostExecute(Integer integer) {
            super.onPostExecute(integer);
            tv1.setText(tv1.getText() + "\nonPostExecute() \n마지막 Value 값: " + integer);
            pb1.setProgress(0);
        }

        //스레드 작업 중(doInBackground) publishProgress 호출 시 실행
        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            int value = Integer.parseInt(values[0]);
            pb1.setProgress(value);
        }

        //cancel() 메소드 호출 시 실행
        @Override
        protected void onCancelled() {
            super.onCancelled();
            tv1.setText("cancel()");
            pb1.setProgress(50);
        }
    }

}

 

결과

 

 

-> 취소

 

 

호출부터 데이터 타입과 전달 그리고 종료까지 최대한 보여주기위해 구현해보았다. 주석을 읽어보면서 하나씩 이해한다면 크게 어렵지 않을 것이다.

 

 

부족한 점, 피드백 환영합니다.

 

감사합니다.

 

 

참고

정재곤, 『Do it! 안드로이드 앱 프로그래밍 - 개정 6판』, 이지스퍼블리싱(주)