W.A 저장소

Thread를 사용하여 다이얼로그 사용법. 본문

Programing

Thread를 사용하여 다이얼로그 사용법.

W.A 2010. 8. 16. 13:53

우선 소스이다.

package com.karyu.threadadialogtest;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class ThreadDialogTestActivity extends Activity {
 /** Called when the activity is first created. */
    static final int PROGRESS_DIALOG = 0;
    Button button;
    ProgressThread progressThread;
    ProgressDialog progressDialog;
   
 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        button = (Button)findViewById(R.id.progressDialog);
        button.setOnClickListener( new OnClickListener() {
   public void onClick(View v) {
    // TODO Auto-generated method stub
    showDialog(PROGRESS_DIALOG);
   }
        });
 }
 @Override
 protected Dialog onCreateDialog(int id) {
  // TODO Auto-generated method stub
  switch( id ) {
  case PROGRESS_DIALOG:
   progressDialog = new ProgressDialog(ThreadDialogTestActivity.this);
   progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  // 있으면 바형태로 / 없으면은 원형태로
   progressDialog.setMessage("Loading...");
   progressThread = new ProgressThread(handler);
   progressThread.start();
   return progressDialog;
  default:
   return null;
  }
 }

 final Handler handler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
   // TODO Auto-generated method stub
   int total = msg.getData().getInt("total");
   progressDialog.setProgress(total);
   if( total >= 100 ) {
    dismissDialog(PROGRESS_DIALOG);
    progressThread.setState(ProgressThread.STATE_DONE);
   }
  }
 };  
 
 @Override
 protected void onPrepareDialog(int id, Dialog dialog) {
  // TODO Auto-generated method stub
  super.onPrepareDialog(id, dialog);
 }
 
 private class ProgressThread extends Thread {
     Handler mHandler;
     final static int STATE_DONE = 0;
     final static int STATE_RUNNING = 1;
     int mState;
     int total;
     
     public ProgressThread(Handler h) {
   // TODO Auto-generated constructor stub
      mHandler = h;
  }

  @Override
  public void run() {
   // TODO Auto-generated method stub
   mState = STATE_RUNNING;
   total = 0;
   while( mState == STATE_RUNNING ) {
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated cach block
     Log.e("ERROR", "Thread Interrupted");
    }
    Message msg = mHandler.obtainMessage();
    Bundle b = new Bundle();
    b.putInt("total", total);
    msg.setData(b);
    mHandler.sendMessage(msg);
    total++;
   }
  }
  
  public void setState(int state) {
   mState = state;
  }
 }
}

위의 소스에서 하는 내용이 바로 개발자가 어떤 작업을 할 때 조금 시간이 오래 걸리는 작업이다 라고 생각이 들면 어플리케이션을 사용하는 사용자의 편의를 위해서(솔직히 3초 이상이 되는 작업이 실행되는동안 화면에 아무것도 보이지 않는다면은 사용자는 어플리케이션이 돌고 있는지 아닌지를 판단하지 못하는 현상.) 개발자는 이 어플리케이션이 지금 어떤한 작업을 하고 있다라고 화면상에 무엇인가를 보여주어야한다.

위의 소스의 순서를 확인하자면
  1. 메인 엑티비티에서 내부 클래스의 ProgressThread를 사용하여 쓰레드 실행(실행시에 mHandle을 넘겨줌.)
  2. 쓰레드는 0.1초마다 total을 1씩 증가시키며 msg를 전송.(추가 적으로 msg는 looper의 메시지큐에 등록되어 looper가 알아서 msg를 꺼내어 msg객체에 들어있는 handleMessage메서드를 실행한다.)
  3. handleMessage메서드의 내용을 확인하여 total이 100과 같거나 크게되면 쓰레드를 멈추게 한다.

몇가지 더 설명을 하자면 onPrepareDialog, onCreateDialog라는 메서드는 showDialog 메서드를 호출하면은 showDialog가 호출하는 메서드이다.

  • onCreateDialog : 인자로 int형의 ID를 입력 받는다. 이 ID를 기준으로 dialog가 생성이 되어 있지 않다면은 dialog를 생성하고 만약 생성이 되어 있다면 onPrepareDialog를 호출하게 된다.
  • onPrepareDialog : 인자로서 int형의 ID와 Dialog객체를 받는다. 이것을 기준으로 하여 이미 생성되어있는 dialog객체를 재사용이 가능하게 만들어준다.

위에서 이야기 한것처럼 위 처럼 showDialog 메서드를 사용하여 dialog를 관리 하게 되면 효율적인 재사용이 가능하다.

한가지 덧붙이자면 Thread를 사용할 때에는 절대로 stop을 사용하지 말고 Thread가 스스로 종료 할 수 있도록 해주는 편이 좋다. 이유는 후에 Thread간 동기화를 할 경우 한 쓰레드가 동기화를 해둔 부분을 다른 Thread가 접근을 하지 못하면 문제가 생기기 때문에 Thread가 스스로 죽으며 걸었던 lock을 풀게 하는쪽이 좋다.