본문 바로가기
안드로이드

[Android] 5. 네트워킹 - 스레드 이해하기(2)

qbang 2019. 7. 25.

안녕하세요 이번 시간에는 5강 네트워킹의 첫번째 강의인 '스레드 이해하기' 두번째 리뷰입니다.

AsyncTask 개념을 알아보면서 실습한 내용을 덧붙여 알아보도록 하겠습니다!

 


'스레드 이해하기 -(1)'에서 정리했던 핸들러에서는 Message 객체가 사용하면 코드가 많아져서 코드를 해석하기 어렵다는 단점이 있습니다.

그러나 AsyncTask는 하나의 클래스 안에 스레드로 동작하는 부분과 UI 객체에 접근하는 부분을 함께 넣어둘 수 있도록 하여 스레드를 사용하는 하나의 작업 단위가 하나의 클래스로 만들어질 수 있습니다.

AsyncTask의 동작 방식(츌처: Android Java Point)

스레드 안에서 실행될 코드는 doInBackground 메소드 안에 넣어두고 UI를 접근할 코드는 onPreExecute,  onProgressUpdate, onPostExecute에 넣어둘 수 있습니다.

AsyncTask도 스레드를 실행하는 것과 같기 때문에 스레드 안에서 실행될 대부분의 코드는 doInBackground 안에 들어가 있게 되며 중간중간 화면에 표시하기 위한 코드 실행을 위해 onProgressUpdate 메소드가 호출됩니다.

onProgressUpdate 메소드는 doInBackground 메소드 안에서 publishProgress 메소드가 호출 될 때 마다 자동으로 호출됩니다.

package com.example.mythread;

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.print.PrintJob;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.style.BackgroundColorSpan;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.util.concurrent.CompletionService;

public class MainActivity extends AppCompatActivity {

    ProgressBar progressBar;
    Handler handler = new Handler();
    CompletionThread completionThread;
    String msg = "";

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

        progressBar = (ProgressBar) findViewById(R.id.progressBar);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  ProgressTask task = new ProgressTask();
                  task.execute("시작");
              }
            }
        );

        completionThread = new CompletionThread();
        completionThread.start();
    }

    class ProgressTask extends AsyncTask<String, Integer, Integer>{
        int value = 0;
        @Override
        protected Integer doInBackground(String... strings) {
            while (true){
                if(value>100){
                    break;
                }
                value += 1;

                publishProgress(value); //onProgressUpdate 호출

                try{
                    Thread.sleep(500);
                }catch (Exception e){}
            }
            return value;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values); // UI를 업데이트하고 싶다면 이 메서드가 호출되는 시점, 여기다가 넣으면 됨

            progressBar.setProgress(values[0].intValue());
        }

        @Override
        protected void onPostExecute(Integer integer) {
            super.onPostExecute(integer);
            Toast.makeText(getApplicationContext(), "완료됨", Toast.LENGTH_LONG).show(); // 프로그레스바가 다 찼을 때 토스트 메시지를 띄움
        }
    }

    class CompletionThread extends Thread{
        public Handler completionHandler = new Handler();
        public void run(){
            Looper.prepare();
            Looper.loop();
        }
    }
}

 위 코드에 대한 결과 화면은 아래와 같습니다.

결과 화면

ProgressBar가 다 차게 되면 '완료됨'이라는 토스트 메시지가 출력되는 것을 확인할 수 있습니다.

이처럼 스레드에서 UI를 접근할 때는 핸들러를 쓰는게 필요지만 AsyncTask를 정의하면 그 안에서 스레드로 동작하는 코드와 UI로 접근하는 코드를 메서드로만 분리해서 코드로 같이 넣어놓을 수 있다는 장점이 있습니다.

이것도 마찬가지로 상황에 맞는 방법을 찾아 이용하시면 될 것 같습니다. 글 읽어주셔서 감사합니다 :)

댓글