안드로이드2015. 2. 2. 16:54

안드로이드에서 스레드는 왜 반드시 써야 하는가, 그리고 어떻게 사용하는지 살펴봤다.

스레드를 쓰다 보면 스레드 간의 동기화를 고려해서 소프트웨어를 설계해야 하고 핸들러 사용으로 복잡하고 번거로운 작업이 될 수 있다.

안드로이드에서는 이런 스레드 작업을 좀 더 쉽게 만들어주는 AsyncTask 추상클래스가 있다.

앞서 살펴본 스레드 사용에 관한 포스트를 보면 시간이 긴 작업은 스레드로 처리하고 UI 변경(화면 조작)은 핸들러에서 처리했었다.

지금부터 살펴볼 AsyncTask는 이런 과정을 하나로 묶을 수 있어 개발 시 불편함을 덜 수 있고 메인 스레드에 부담도 덜어 준다고 하니 살펴보자.

AsyncTask는 메인 클래스 안에 서브 클래스로 사용해야 한다고 하니 유의해서 간단히 소스를 작성해보자.

(Usage - AsyncTask must be subclassed to be used.)

package kr.corej.myapplication;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends Activity {

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

    public void mOnClick(View view) {
        switch (view.getId()) {
            case R.id.button:
                try {
                    new DownloadFilesTask().execute(new URL("파일 다운로드 경로1"), new URL("파일 다운로드 경로2"));
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
                break;
        }
    }

    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Long doInBackground(URL... urls) {
            int count = urls.length;
            long totalSize = 0;
            for (int i = 0; i < count; i++) {
                // 내려받는 파일 size 합산 작업
                // totalSize += Downloader.downloadFile(urls[i]);

                publishProgress((int) ((i / (float) count) * 100));
                // Escape early if cancel() is called
                if (isCancelled()) break;
            }
            return totalSize;
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            // 파일 다운로드 퍼센티지 표시 작업
            // setProgressPercent(progress[0]);
        }

        @Override
        protected void onPostExecute(Long result) {
            // 다 받아진 후 받은 파일 총용량 표시 작업
            // showDialog("Downloaded " + result + " bytes");
        }

        @Override
        protected void onCancelled(Long aLong) {
            super.onCancelled(aLong);
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

실제 소스를 돌려보면 아랫부분에서 (제대로 된 URL이 아니라서) 멈춰버리니 대충 소스만 봐보자.

                try {
                    new DownloadFilesTask().execute(new URL("파일 다운로드 경로1"), new URL("파일 다운로드 경로2"));
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }

URL 사용 때문에 try catch로 묶은 것이고 실제 AsyncTask를 사용하면 스레드 작업은 매우 간단하게 생성, 실행할 수 있다.


    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long>

AsyncTask's generic types (AsyncTask<Params, Progress, Result>)

비동기 작업에서 사용하는 세 가지 유형이 다음과 같다.

Params - 파라미터 타입은 작업 실행 시에 송신.

(doInBackground 파라미터 타입이 되며, execute 메소드 인자 값이 된다.)

Progress - doInBackground 작업 시 진행 단위의 타입.

(onProgressUpdate 파라미터 타입)

Result - doInBackground 리턴값.

(onPostExecute 파라미터 타입)


Void 타입 사용 시에는 간단하게 작성할 수 있다.

    private class DownloadFilesTask extends AsyncTask<Void, Void, Void> { ... }


각 메소드에 대해서 간략히 보고 넘어가자.

void onPreExecute()

doInBackground 시작 전에 호출되어 UI 스레드에서 실행된다. 주로 로딩바나 Progress 같은 동작 중임을 알리는 작업을 작성한다.


Result doInBackground(Params... prams)

실제 스레드 작업을 작성하는 곳이며 execute에서 전달한 params 인수를 사용할 수 있다.

 

void onProgressUpdate(Progress... values)

publishProgress()를 통해 호출되며 UI 스레드에서 실행된다. 파일 내려받는다고 치면 그때 퍼센티지 표시 작업 같은 걸 작성한다.


void onPostExecute(Result result)

doInBackground 작업의 리턴값을 파라미터로 받으며 작업이 끝났음을 알리는 작업을 작성한다.


끝으로 AsyncTask는 execute(Runnable runnable) 메소드도 있어서 간단한 스레드 작업을 할 때도 사용할 수 있다.

        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                // 스레드 작업
            }
        });



코어제이 홈페이지 제작 소개


코어제이 캔디 앱 소개


Posted by 코어제이