2013년 5월 26일 일요일

[Android] AsyncTask를 이용한 ProgressDialog 사용 예제

ProgressDialog 를 띄워서 현재 진행중인 작업의 진행률을 표시해보자.

싱글쓰레드를 사용하면 UI 갱신이 안되서 멀티쓰레드를 써야하는데

Thread를 직접 생성해서 사용할 수 있지만

AsyncTask 라는 쓰기 좋은 녀석이 있다는 사실.

아래는 공식 레퍼런스

http://developer.android.com/intl/ko/reference/android/os/AsyncTask.html

http://developer.android.com/intl/ko/reference/android/app/ProgressDialog.html


이번 예제는 버튼을 누르면 AsyncTask를 사용하여

ProgressDialog를 띄우고 진행 중인 작업 정보를 갱신해주면서

작업 종료시에 Dialog 닫고 Toast 메시지 하나 띄우는 예제임.

 
 

ProgressDlgTest.java
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;

public class ProgressDlgTest extends AsyncTask< Integer//excute()실행시 넘겨줄 데이터타입
            , String//진행정보 데이터 타입 publishProgress(), onProgressUpdate()의 인수 
            , Integer//doInBackground() 종료시 리턴될 데이터 타입 onPostExecute()의 인수
> {
 //ProgressDialog를 멤버로 하나 넣어줌
 private ProgressDialog mDlg;
 private Context mContext;
 
 public ProgressDlgTest(Context context) {
  mContext = context;
 }
 
 //onPreExecute 함수는 이름대로 excute()로 실행 시 doInBackground() 실행 전에 호출되는 함수
 //여기서 ProgressDialog 생성 및 기본 세팅하고 show()
 @Override
 protected void onPreExecute() {
  mDlg = new ProgressDialog(mContext);
  mDlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  mDlg.setMessage("작업 시작");
  mDlg.show();
        
        super.onPreExecute();
    }

 //doInBackground 함수는 excute() 실행시  실행됨
 //여기서 인수로는 작업개수를 넘겨주었다.
 @Override
 protected Integer doInBackground(Integer... params) {
  
  final int taskCnt = params[0];
  //넘겨받은 작업개수를 ProgressDialog의 맥스값으로 세팅하기 위해 publishProgress()로 데이터를 넘겨준다.
  //publishProgress()로 넘기면 onProgressUpdate()함수가 실행된다.
  publishProgress("max", Integer.toString(taskCnt));
  
  //작업 진행, 여기선 넘겨준 작업개수 * 100 만큼 sleep() 걸어줌
  for (int i = 0; i < taskCnt; ++i) {
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   //작업 진행 마다 진행률을 갱신하기 위해 진행된 개수와 설명을 publishProgress() 로 넘겨줌.
   publishProgress("progress", Integer.toString(i), "작업 번호 " + Integer.toString(i) + "번 수행중");
  }
  
  //작업이 끝나고 작업된 개수를 리턴 . onPostExecute()함수의 인수가 됨
  return taskCnt;
 }
 
 //onProgressUpdate() 함수는 publishProgress() 함수로 넘겨준 데이터들을 받아옴
 @Override
    protected void onProgressUpdate(String... progress) {
  if (progress[0].equals("progress")) {
   mDlg.setProgress(Integer.parseInt(progress[1]));
   mDlg.setMessage(progress[2]);
  }
  else if (progress[0].equals("max")) {
   mDlg.setMax(Integer.parseInt(progress[1]));
  }
    }
 
 //onPostExecute() 함수는 doInBackground() 함수가 종료되면 실행됨
  @Override
     protected void onPostExecute(Integer result) {
   mDlg.dismiss();
   Toast.makeText(mContext, Integer.toString(result)+ "개의 작업 완료", Toast.LENGTH_SHORT).show();
 }
}


Main.java
public class Main extends Activity {
    /** Called when the activity is first created. */
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button btn = (Button) findViewById(R.id.btn_popup);
        btn.setOnClickListener(new Button.OnClickListener() {
         public void onClick(View v) {
          //ProgressDlgTest 실행
          new ProgressDlgTest(Main.this).execute(100);
         }
        });
    }
}

AsyncTask 사용하면서 삽질을 좀 했는데

주의할 점이 많으니 사용 전 꼭 공식레퍼런스를 읽어보기.

첨엔 뭣 모르고 doInBackground() 함수내에서 ListView 갱신을 했더니 프로그램이 그냥 죽더라.

한참 헤매다가 AsyncTask 구조를 좀 이해하고 해결;;

결론은 UI 갱신은 publishProgress()를 사용해서 onProgressUpdate()콜백에서 처리해야 됨

암튼 직접 Thread 생성해서 작업하는거 보다 좋음




댓글 없음:

댓글 쓰기