웹 서버와 같은 원격 서버에 접속한 후 웹페이지를 요청할 때 응답이 늦어지거나 응답이 없으면 앱이 대기하고 있는 상황이 지속되는 문제가 생긴다.
이런 경우에는 기본적으로 별도의 스레드를 만들어 처리하게 된다.
하지만 버튼을 클릭하여 간단하게 접속 처리하는 경우에는 메인 스레드 내에서 지역 시간을 주는 것만으로도 UI의 멈춤 현상을 방지할 수 있다.
핸들러로 지연 시간을 주었을 때 핸들러로 실행되는 코드는 메시지 큐를 통과하면서 순차적으로 실행되기 때문에 UI 객체들에 영향을 주지 않으면서 지연 시간을 두고 실행된다.
대화상자를 띄우고 대화상자의 버튼을 누르면 핸들러를 사용해 5초 후에 코드가 실행되도록 만들어보았다.
먼저 activity_main.xml 레이아웃에 텍스트뷰와 버튼을 추가하였다.
MainActivity.java파일의 코드를 수정하였다.
public class MainActivity extends AppCompatActivity {
TextView textView;
Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
request();
}
});
}
private void request(){
String title = "원격 요청";
String message = "데이터를 요청하시겠습니까?";
String titleButtonYes = "예";
String titleButtonNo = "아니오";
AlertDialog dialog = makeRequestDialog(title, message, titleButtonYes, titleButtonNo);
dialog.show();
textView.setText("대화상자 표시중...");
}
private AlertDialog makeRequestDialog(CharSequence title, CharSequence message, CharSequence titleButtonYes, CharSequence titltButtonNo) {
AlertDialog.Builder requestDialog = new AlertDialog.Builder(this);
requestDialog.setTitle(title);
requestDialog.setMessage(message);
requestDialog.setPositiveButton(titleButtonYes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
textView.setText("5초 후에 결과 표시됨");
handler.postDelayed(new Runnable() {
@Override
public void run() {
textView.setText("요청 완료됨.");
}
}, 5000);
}
});
requestDialog.setNegativeButton(titltButtonNo, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
return requestDialog.create();
}
}
버튼을 누르면 새로 정의한 request() 메소드가 실행되게 하였다.
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
request();
}
});
}
private void request(){
String title = "원격 요청";
String message = "데이터를 요청하시겠습니까?";
String titleButtonYes = "예";
String titleButtonNo = "아니오";
AlertDialog dialog = makeRequestDialog(title, message, titleButtonYes, titleButtonNo);
dialog.show();
textView.setText("대화상자 표시중...");
}
request 메소드는 AlertDialog를 이용하여 대화상자를 보여준다.
대화상자는 새로 정의한 makeRequestDialog() 메소드를 이용해 만든다.
private AlertDialog makeRequestDialog(CharSequence title, CharSequence message, CharSequence titleButtonYes, CharSequence titltButtonNo) {
AlertDialog.Builder requestDialog = new AlertDialog.Builder(this);
requestDialog.setTitle(title);
requestDialog.setMessage(message);
requestDialog.setPositiveButton(titleButtonYes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
textView.setText("5초 후에 결과 표시됨");
handler.postDelayed(new Runnable() {
@Override
public void run() {
textView.setText("요청 완료됨.");
}
}, 5000);
}
});
requestDialog.setNegativeButton(titltButtonNo, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
return requestDialog.create();
}
대화상자의 '예' 버튼을 누르면 핸들러 객체의 postDelayed 메소드를 사용해 약간의 시간이 지난 후 코드가 실행되게 만들었다.
requestDialog.setPositiveButton(titleButtonYes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
textView.setText("5초 후에 결과 표시됨");
handler.postDelayed(new Runnable() {
@Override
public void run() {
textView.setText("요청 완료됨.");
}
}, 5000);
}
});
핸들러는 메시지 큐를 사용하므로 메시지들을 순서대로 처리하지만 메시지를 넣을 때 시간을 지정하면 원하는 시간에 메시지를 처리하게 만들 수 있다.
이는 일정 시간 후에 실행시킬 때 유용하게 사용된다.
시간을 지정할 때는 핸들러의 sendMessage 메소드와 유사한 다음의 메소드를 사용할 수 있다.
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public boolean sendMessageDelayed(Message msg, long delayMillis)
첫 번째 메소드는 메시지를 보낼 때 시간을 지정할 수 있고,
두 번째 메소드는 일정 시간이 지난 후 실행되도록 설정할 수 있다.
Runnable 객체를 실행하는 post 메소드도 postAtTime과 위에서 사용한 postDelayed 메소드가 있어 같은 기능을 수행한다.