스마트기기개발관련/안드로이드 개발

안드로이드 쓰레드 AsyncTask Android example 쓰레드 AsyncTask 관련

AlrepondTech 2015. 5. 21. 23:06
반응형

 

 

 

 

 

=================================

=================================

=================================

 

 

 

 

 

출처: http://jo.centis1504.net/?p=966

 

자바의 Swing에서도 마찬가지이지만, 같은 스레드에서 시간이 걸리는 처리를 실행하게 되면 UI가 멈추거나
유져가 입력한 처리를 바로 개시하지 못하는 경우가 많다.

Android에서는 이런 처리들을 AsyncTask 로 정의하여 메인 스레드와 별도로 백그라운드에서 처리한다.
(보통 Thread를 Androind에 최적화하여 Interface를 정의했다고 보면 될듯)

클래스에 지정하는 3개의 Generic의미는
첫번째가 doInBackground 의 인수,
두번째가 progress의 인수,
세번째가 결과(리턴)값의 인수이다.

 

 

이렇게 정의하고 실제 호출할때는

SampleAsyncTask task = new SampleAsyncTask(“taskA”);
task.execute((Long)1);

과 같이 백그라운드에서 실행한다.

실행중인지의 체크 방법

 

 

This entry was posted in Android. Bookmark the permalink.

 

 

 

 

=================================

=================================

=================================

 

 

 

출처: http://stackoverflow.com/questions/9671546/asynctask-android-example

 

public class AsyncTaskActivity extends Activity {     Button btn;     /** Called when the activity is first created. */     @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.main);          btn = (Button) findViewById(R.id.button1);         btn.setOnClickListener((OnClickListener) this);     }      public void onClick(View view){         new LongOperation().execute("");     }      private class LongOperation extends AsyncTask<String, Void, String> {         @Override         protected String doInBackground(String... params) {             for(int i=0;i<5;i++) {                 try {                     Thread.sleep(1000);                 } catch (InterruptedException e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }             }             TextView txt = (TextView) findViewById(R.id.output);             txt.setText("Executed");             return null;         }          @Override         protected void onPostExecute(String result) {         }          @Override         protected void onPreExecute() {         }          @Override         protected void onProgressUpdate(Void... values) {         }     } }

 

 

 

=================================

=================================

=================================

 

 

 

출처: http://arabiannight.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9CAndroid-AsyncTask-%EC%82%AC%EC%9A%A9%EB%B2%95

 

안드로이드/Android AsyncTask 사용법

 

 

안드로이드 AsyncTask 사용법에 대해 알아 보겠습니다. 안드로이드에는 UI 를 총괄하는 메인Thread가 존재 한고 있는데요.([안드로이드/Android Android에서 Thread(쓰레드) 란 무엇 인가?]메인Thread 외에는 일반Thread들이 안드로이드 UI 화면을 처리할 수 없습니다. 그렇기 때문에 메인Thread와 일반Thread 를 잘 핸들링 해서 사용해야 하는데, 여간 번거로운 일이 아닙니다.

 

그렇기 때문에, Android 에서는 AsyncTask 라는 객체를 지원하는데요. AsyncTask는 UI 처리 및 Background 작업 등 을 하나의 클래스에서 작업 할 수 있게 지원해 줍니다. 쉽게말해 메인Thread와 일반Thread를 가지고 Handler를 사용하여 핸들링하지 않아도 AsyncTask 객체하나로 편하게 UI를 수정 할 수 있고, Background 작업을 진행 할 수 있습니다. 각각의 주기마다 CallBack 메서드를 사용해서 말이죠.

 

큰 장점입니다. 

 

자 그럼 예제 소스를 살펴 볼까요?

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package arabiannight.tistory.com.aynctask;
 
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
 
public class TestAsyncTaskActivity extends Activity {
     
    private MyAsyncTask myAsyncTask;
     
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
         
        myAsyncTask = new MyAsyncTask();
        myAsyncTask.execute("80", "90", "100", "110");
         
    }
     
    // AsyncTask클래스는 항상 Subclassing 해서 사용 해야 함.
    // 사용 자료형은
    // background 작업에 사용할 data의 자료형: String 형
    // background 작업 진행 표시를 위해 사용할 인자: Integer형
    // background 작업의 결과를 표현할 자료형: Long
    // 인자를 사용하지 않은 경우 Void Type 으로 지정.
    public class MyAsyncTask extends AsyncTask<string, void,="" string=""> {
 
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
         
        @Override
        protected String doInBackground(String... params) {
             
            String sum = "";
             
            if(params != null){
                for(String s : params){
                    sum += s;
                }
            }
            return sum;
        }
         
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
             
            if(result != null){
                Log.d("ASYNC", "result = " + result);
            }
             
        }
         
        @Override
        protected void onCancelled() {
            super.onCancelled();
        }
         
    }
     
}
//</string,>

 

 

1. onPreExecute() : Background 작업 시작전에 UI 작업을 진행 한다.

 

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

 

 

2. doInBackground() : Background 작업을 진행 한다.

 

 

 @Override 
 protected String doInBackground(String... params) {
       super.onPreExecute(); 
 }

 

 

3. onPostExecute() : Background 작업이 끝난 후 UI 작업을 진행 한다.

 

 

 @Override 
 protected void onPostExecute(String result) 
{
       super.onPreExecute(); 
 }

 

 

 

 

 

FLOW를 살펴 보자면,

[onPreExecute()] -> [doInBackground()] -> [

onPostExecute()] 순서가 됩니다.

 

 

 

 

=================================

=================================

=================================

 

 

 

 

출처: http://daehyub71.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9CAsyncTask%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC

 

 

AsyncTask를 이야기하려다 보니 프로그래스바 하나 넣어보겠다고 3~4일을 고생해서 겨우 찾아냈던 기억이 새록새록하면서 애증이 담겨있는 class라는 생각이 듭니다. 하지만 AsyncTask는  thread+handler라는 나름 강력한 기능을 가지고 있어서 제대로만 알아두면 유용한 클래스가 되지 않을까 싶습니다.

혹시 책만 보고 도전했다가 저같이 고생하지 않았으면 하는 맘에 이 글을 적어봅니다.

왜 AsyncTask인가?

AsyncTask라는 클래스 이름은 Asynchronous Task의 줄임이며, UI스레드의 입장에서 볼 때 비동기적으로 작업이 수행되기 때문에 붙여진 이름이다.

sync 와 async의 용어는 네트워크이나 커널 프로세스에서 많이 나오는 용어인데요.저야 뭐 이론적으로는 공부한지 하도 오래되어서 그냥 프로그램 하면서 경험으로 이야기를 해보겠습니다.

보통 sync는 직렬회로라고 보시면 될듯합니다. 반면 async는 병렬회로라고 보시면 될 듯 합니다.

일이 순차적으로 진행되면서 하나가 해결되면 그다음 일이 진행되는 식으로 네트워크에서는 요청(request)를 보내면 항상 응답(response)을 받아야 진행하는 방식으로 구현하면 sync방식,아니고 계속 요청을 보내는 통로와 응답을 받는 통로를 따로 만들어두면 async방식이라고 불리죠.

AsyncTask는 UI 처리 및 Background 작업 등 을 하나의 클래스에서 작업 할 수 있게 지원해 줍니다. 쉽게말해 메인Thread와 일반Thread를 가지고 Handler를 사용하여 핸들링하지 않아도 AsyncTask 객체하나로 각각의 주기마다 CallBack 메서드가 편하게 UI를 수정 할 수 있고, Background 작업을 진행 할 수 있습니다.

AsyncTask사용법

Object로부터 상속하는 AsyncTask는 Generic Class이기 때문에 사용하고자 하는 type을 지정해야 합니다.
AsyncTask클래스는 기본적으로 3개의 제네릭 타입(Params,Progress,Result)을 제공하고 있는 추상 클래스다.Generic type은 실행시간에 데이터 타입을 정할 수 있는 특수한 타입이라고 이해하시면 될 듯 합니다.

Params: background작업 시 필요한 data의 type 지정
Progress: background 작업 중 진행상황을 표현하는데 사용되는 data를 위한 type 지정
Result: 작업의 결과로 리턴 할 data 의 type 지정

예)

1
AsyncTask<DataInfo[], Integer, Void> InsertTask = new InsertCallTask().execute(datainfo4);

미사용 타입에 대해서는 Void를 전달하면 된다.  

AsyncTask Callbak 함수

언제 호출되여 무슨 작업을 하는가와 함께 각 메서드가 어떤 스레드에서 실행되는가도 중요하다. doInBackground메서드 외에는 모두 UI스레드에서 실행되므로 메인스레드의 view들을 안전하게 참조할 수 있습니다.

주로 쓰게 되는 콜백메스드 4개에 대해 설명해보겠습니다.

● void onPreExecute()

작업이 시작되기 전에 호출되며 UI스레드에서 실행되는 메소드,계산을 위한 초기화나 프로그래스 대화상자를 준비하는 등의 작업을 수행합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 이곳에 포함된 code는 AsyncTask가 execute 되자 마자 UI 스레드에서 실행됨.
// 작업 시작을 UI에 표현하거나
// background 작업을 위한 ProgressBar를 보여 주는 등의 코드를 작성.
@Override
protected void onPreExecute() {
       // 작업을 시작하기 전 할일
    dialog = new ProgressDialog(DetailActivity.con);
    dialog.setTitle("이미지 다운로드중");
    dialog.setMessage("잠시만 기다리세요...");
    dialog.setIndeterminate(true);
    dialog.setCancelable(true);
    dialog.show();
                 
    super.onPreExecute();
}  

● Result doInBackground(Params... params)

백그라운드 스레드로 동작해야 하는 작업을 실행한다. execute메서드로 전달한 data tye이 params 인수로 전달되는데 여러개의 인수를 전달할 수 있으므로 배열 타입으로 되어 있습니다. 그래서 하나의 인수만 필요하다면 params[0]만 사용하면 됩니다. 작업 중에 publishProgress 메소드를 호출하여 작업 경과를 UI스레드로 display할 수 있으며 작업결과는 Result타입으로 리턴됩니다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
@Override
protected Bitmap doInBackground(String... urls) {
    /* http://snowbora.com/417 참고
     * */
    final HttpClient client         = AndroidHttpClient.newInstance("Android");
    final HttpGet getRequest        = new HttpGet(urls[0]);
    final int IMAGE_MAX_SIZE        = 1280;
     
    try
    {
        HttpResponse response = client.execute(getRequest);
        final int statusCode = response.getStatusLine().getStatusCode();
         
        if (statusCode != HttpStatus.SC_OK)
        {
            return null;
        }
 
        final HttpEntity entity = response.getEntity();
         
        if (entity != null)
        {
            InputStream inputStream = null;
             
            try
            {
                inputStream = entity.getContent();
                 
                BitmapFactory.Options bfo   = new BitmapFactory.Options();
                bfo.inJustDecodeBounds      = true;
 
                BitmapFactory.decodeStream(new FlushedInputStream(inputStream), null, bfo);
                 
                if(bfo.outHeight * bfo.outWidth >= IMAGE_MAX_SIZE * IMAGE_MAX_SIZE)
                {
                    bfo.inSampleSize = (int)Math.pow(2, (int)Math.round(Math.log(IMAGE_MAX_SIZE / (double) Math.max(bfo.outHeight, bfo.outWidth)) / Math.log(0.5)));
                }
                bfo.inJustDecodeBounds = false;
                 
                response = client.execute(getRequest);
                final int nRetryStatusCode = response.getStatusLine().getStatusCode();
                 
                if (nRetryStatusCode != HttpStatus.SC_OK)
                {
                    return null;
                }
                 
                final HttpEntity reEntity = response.getEntity();
                 
                if (reEntity != null)
                {
                    InputStream reInputStream = null;
                     
                    try
                    {
                        reInputStream = reEntity.getContent();
                        final Bitmap imgBitmap = BitmapFactory.decodeStream(new FlushedInputStream(reInputStream), null, bfo);
                         
                        return imgBitmap;
                    }
                    finally
                    {
                         if (reInputStream != null)
                         {
                             reInputStream.close();
                         }
                          
                         reEntity.consumeContent();
                    }
                }
            }
            finally
            {
                if (inputStream != null)
                {
                    inputStream.close();
                }
                 
                entity.consumeContent();
            }
        }
    }
    catch (IOException e)
    {
        getRequest.abort();
    }
    catch (IllegalStateException e)
    {
        getRequest.abort();
    }
    catch (Exception e)
    {
        getRequest.abort();
    }
    finally
    {
        if ((client instanceof AndroidHttpClient))
        {
            ((AndroidHttpClient)client).close();
        }
    }
     
    return null;
     
}

● void onProgressUpdate(Progress... values)

doInBackground에서드에서 publishProgress(Progress...) 메소드를 호출할 때 호출되며 작업의 진행사항을 표시하기 위해 호출됩니다. UI스레드에서 프로그래스바에 진행 상태 표시하는 역할 수행합니다.

1
2
3
4
5
// onInBackground(...)에서 publishProgress(...)를 사용하면
protected void onProgressUpdate(Integer... progress) {
    Log.d("LOST","onProgressUpdate:["+progress[0]+"]");
    dialog.setProgress(progress[0]);
}

 

● void onPostExecute(Result result)

doInBackground에서드의 작업 결과를 UI반영하는 역할을 담당하는 메소드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// onInBackground(...)가 완료되면 자동으로 실행되는 callback
// 이곳에서 onInBackground가 리턴한 정보를 UI위젯에 표시 하는 등의 작업을 수행함.
// (예제에서는 작업에 걸린 총 시간을 UI위젯 중 TextView에 표시함)
@Override
protected void onPostExecute(Bitmap imgBitmap) {
    if (imgBitmap != null)
    {
        imgView.setImageBitmap(imgBitmap);
        imgView.setVisibility(ImageView.VISIBLE);
        textview.setVisibility(TextView.GONE);
    }else{
        //textview = (TextView)findViewById(R.id.textView1);
        textview.setText("등록된 사진이 없습니다.");
        textview.setTextSize(20);
        textview.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
        textview.setVisibility(TextView.VISIBLE);
        imgView.setVisibility(ImageView.GONE);
    }
 
    dialog.dismiss();
}
일반적으로

 AsyncTask를 구현할 때 별도 스레드로 동작해야 할 코드는 doInBackground()메소드에 작성하고, 이 메소드가 실행되기 전에 먼저 처리할 코드가 있다면 onPreExecute()메소드에 작성하면 됩니다. 그리고 doInBackground()메소드가 완료된 후에 처리해야할 코드는 onPostExecute()메소드에 작성하고, doInBackground()메소드가 동작하는 동안 주기적으로 반영해야 할 작업이 있다면 onProgressUpdate()메소드에 작성하면 됩니다.

이 때 주의사항은 3개의 제네릭 타입과 메소드 타입을 잘 맞춰어야 원하는 결과가 나온다는 겁니다.이게 잘 안 맞아서 저는 코딩하면서 구현이 제대로 안되고 한참 고생했던 기억이 있습니다. 꼭 doInBackground, onPreExecute, onPostExecute의 리턴값과 파라미터를 잘 매칭해야 합니다.

 

참고사이트

 

 

 

=================================

=================================

=================================

 

 

 

출처: http://ismydream.tistory.com/130

 

 

안드로이드 비동기 처리하기 AsyncTask

 

비동기 처리를 하기 위해서는 별도의 Thread 를 생성하여 public void run()  메소드를 구현하면 되지만 안드로이드에서는 직접 Thread 를 생성하기 보다는 AsyncTask 를 사용하길 권장합니다.

AsyncTask 내부에는 자체 ThreadPool 이 있어 Thread 가 무한정 늘어나 메모리에 부담을 주지 않도록 관리 하고 있기 때문에따로 ThreadPool 을 관리하지 않는다면 AsyncTask 를 사용하는게 무난할 것 같습니다.

 

아래는 비동기적으로 ImageView에 Bitmap을 로드하는 코드입니다.

 

doInBackground 메소드는 기존의 Thread 에서의 run() 메소드라고 보시면 됩니다.

AsyncTask 는 처리할 데이터에 따라 파라미터 타입을 정의할 수 있습니다. 정의하는 부분은 클래스를 정의하는 부분에 있습니다.

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap>{


 

 Integer   execute, doInBackground 의 파라미터 타입
 Void   onProgressUpdate 의 파라미터 타입
 Bitmap   
doInBackground 의 리턴값, onPostExecute 의 파라미터로 설정됩니다.

 


AsyncTask 소스를 보면 좀더 정확히 확인하실 수 있습니다.

 

또한 AsyncTask 는 실행 전후로 전처리, 후처리를 할 수 있는 콜백 메소드를 제공합니다.

onPreExecute(), onPostExecute( Bitmap)

 

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap>{

private final WeakReference<ImageView> imageViewReference;

private int data = 0;

 

public BitmapWorkerTask( ImageView imageView){

// WeakReference 를 사용하는 이유는 image 처럼 메모리를 많이 차지하는 객체에 대한 가비지컬렉터를 보장하기 위해서입니다.

imageViewReference = new WeakReference<ImageView>(imageView);

}

 

@Override

protected Bitmap doInBackground( Integer... params){

data = param[0];

return decodeSampledBitmapFromResource( getResources(), data, 100, 100);

}

 

@Override

protected void onPostExecute( Bitmap bitmap){

if( imageReference != null && bitmap != null){

final ImageViewReference imageView = imageViewReference.get();

if( imageView != null){

imageView.setImageBitmap( bitmap);

}

}

}

}

 

위처럼 AsyncTask 를 확장하는 클래스를 생성한후 실행하면 됩니다.

public void loadBitmap( int resId, ImageView imageView){

BitmapWorkerTask task = new BitmapWorkerTask( imageView);

task.execute( resId);

}

 

AsyncTask 는 execute( Runnable) 메소드도 제공하기 때문에 별도의 스레드 작업을 할때도 사용할 수 있습니다.

[별도의 카메라 앱을 실행시켜 사진을 촬영하는 코드]

AsyncTask.execute( new Runnable(){

public void run() {

Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

try{

mImageF = createImageFile();

// 이미지가 저장될 파일은 카메라 앱이 구동되기 전에 세팅해서 넘겨준다.

openCameraIntent.putExtra( MediaStore.EXTRA_OUTPUT, Uri.fromFile( mImageF)); 

mActivity.startActivityForResult( openCameraIntent, RequestCodes.REQUESTCODE_CAMERA_PICTURE);

}catch( IOException e){

e.printStackTrace();

}

}

});

 
 

 

 

 

=================================

=================================

=================================

 

 

 

 

 

 

반응형