자바 다이얼로그 종료 - jaba daieollogeu jonglyo

안드로이드 애플리케이션을 개발하다 보면, Dialog 부류의 위젯을 많이 사용하게 된다. 그리고 이 위젯을 화면에 보여주고 완료하면 dismiss()를 호출해서 종료를 시킨다. 이 과정에서 java.lang.NullPointerException이 발생할 수 있다. 그리고 Activty가 Dialog보다 먼저 종료(finish() 호출되는 등)가 되는 상황에서는 아래의 예외를 발생시킨다. java.lang.IllegalArgumentException: View not attached to window manager.

아래는 API 문서의 구조로, Dialog 부류의 최상위는 DialogInterface라는 것을 알 수 있다.

자바 다이얼로그 종료 - jaba daieollogeu jonglyo

위 구조에서 dismiss()를 가지고 있는 클래스는 Dialog로, 이 클래스의 구조도는 다음과 같다.

자바 다이얼로그 종료 - jaba daieollogeu jonglyo

ProgressDialog를 사용하면서 dismiss()를 하는 일반적이 코드는 다음과 같다.

if(progressdialog != null && progressdialog.isShowing())
{
   progressdialog.dismiss();
}

이 코드는 대체로 동작을 하지만, 위에서 언급한 예외가 발생할 수 있기에, 위의 코드를 try ~ catch로 감싸는 코드를 종종 보게 된다. 그래서 dismiss()를 안전하고 verbose하지 않게 처리하기 위해서 아래와 같은 간단한 유틸 클래스를 사용하면 좋다.

public class DialogDismisser {
	public static void dismiss(DialogInterface d) {
		if(d == null)
			return;
		
		try {
			if(d instanceof AlertDialog) {
				if(((AlertDialog) d).isShowing())
					((AlertDialog)d).dismiss();
				
				return;
			}
					
			if(d instanceof ProgressDialog) {
				if(((ProgressDialog) d).isShowing())
					((ProgressDialog)d).dismiss();
				
				return;
			}
			
			if(d instanceof Dialog) {
				if(((Dialog) d).isShowing())
					((Dialog)d).dismiss();
				
				return;
			}
		} catch(Exception e) {
			Log.e("dissmiss error", e);
		}
	}

	public static void dismiss(DialogInterface d1, DialogInterface d2) {
		dismiss(d1);
		dismiss(d2);
	}
}

이 클래스를 사용해서 각종 Dialog의 dismiss()를 안전하게 종료시킬 수 있다. 혹시 cancel()을 사용한다면 이 클래스와 동일한 형태로 작성해서 사용하면 된다.

나만을 위한 블로그

Android

[Android] 커스텀 다이얼로그로 액티비티 종료하기

참깨빵위에참깨빵 2019. 12. 7. 18:10

써본 적이 없던 커스텀 다이얼로그를 써 보고 싶어서 쓰던 중 확인 버튼을 누르면 액티비티를 종료시켜야 할 상황이 생겼다.

그래서 방법을 생각해봤다.

1. 커스텀 다이얼로그의 xml, 자바 파일을 만든다.

2. 자바 파일에서 확인 버튼에 클릭 리스너를 만든다.

3. 클릭 리스너 안에 메인 액티비티를 종료시키는 코드를 넣는다.

이런 순서로 구현하면 되겠다 싶어 그대로 해봤다.

그러나 3번에서 막혔다. 다이얼로그는 dismiss()를 써서 종료시킨다고 해도 메인 액티비티는 어떻게 종료시키지?

답은 컨텍스트에 있었다.

커스텀 다이얼로그 안에 Context를 전역 변수로 선언하고, 다이얼로그 확인 버튼에서 context 변수를 해당 액티비티로 캐스팅하면 된다.

그러면 이 컨텍스트를 통해 finish()를 호출할 수 있게 되고, 내가 원하는 액티비티를 종료할 수 있게 된다.

아래는 내가 사용한 코드다. setOnClickListener() 안의 코드가 람다식으로도 가능하다는 메시지가 나와서 바꿨기 때문에 코드가 람다식 형태다.

ok.setOnClickListener(view -> {
Toast.makeText(context, "메인 액티비티 종료", Toast.LENGTH_SHORT).show();
dialog.dismiss();
((MainActivity)context).finish(); <- 이 부분이 중요하다
});

JOptionPane은 보통 Alert 형식으로 많이 쓰는데, 메시지를 띄우고 몇 초 뒤에 자동으로 닫히는 것을 원하는
사람이 있다면 이 소스가 도움이 될 것 이다.

순서가 매우 중요하다.

new Thread() {  
              public void run() {  
                  for (int i = 0; i < 3; i++) {  
                      try {  
                          Thread.sleep(2000);  
                      } catch (InterruptedException e) {  
                      }  
                      JOptionPane.getRootFrame().dispose();  
                  }  
              }  
          }.start();  
    JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "시스템이 2초 후 재시작 됩니다.");

스레드를 먼저 돌려서 2초뒤에 Dialog을 닫도록 설정한다. 그럼 따로 계속 동작할테고,
그동안 Dialog를 띄우면 Thread에 의해서 닫히는 것을 확인해 볼 수 있다.

여러가지 다양한 용도로 쓸 수 있다.

본인은 위와 같이 시스템을 재시작 하는 용도로 사용했다. 물론 재시작을 위한 소스가 뒤에 더 있지만..

  • 아래와 같이 팝업으로 주로 사용자에게 오류나 경고 또는 짧은 메시지를 전달하는 데 사용되는 박스
JOptionPane.showMessageDialog(null, "내용입니다");

JOptionPane

  • 팝업창을 띄워주는 스윙 클래스
    사용자가 입력, 확인, 알림 창을 만들수 있는 클래스

-총 4가지의 메소드가 존재한다.
1. showMessageDialog
2. showInputDialog
3. showConfirmDialog
4. showOptionDialog

showMessageDialog

단순 메시지를 출력한다. 입력값을 받지 않기 때문에 리턴값이 존재하지 않는다.

JoptionPane.showMessageDialog(Component parentComponent, Object msg, String title, int messageType);
  • messageType
    -다이얼로그의 종류를 지정해 줄 수 있다.
    -ERROR_MESSAGE INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE,PLAIN_MESSAGE

ex)JOptionPane.showMessageDialog(null, "대화상자내용", "대화상자제목부분", JOptionPane.WARNING_MESSAGE);

ex) JOptionPane.showMessageDialog(null, "대화상자내용", "대화상자제목부분", JOptionPane.PLAIN_MESSAGE);

ex) JOptionPane.showMessageDialog(null, "대화상자내용", "대화상자제목부분", JOptionPane.INFORMATION_MESSAGE);


showInputDialog

-입력 다이얼로그다. 한 줄을 입력받을 수 있는 메소드
-String 형태로 그 입력값이 저장되고, 입력이 없을시(취소 선택시) null 값이 저장된다.

String name = JOptionPane.showInputDialog("이름을 입력하세요");
System.out.print("이름 : " + name);

팝업창

자바 다이얼로그 종료 - jaba daieollogeu jonglyo

'디디' 입력시


showConfirmDialog

-사용자에게 y/n 와 같은 응답을 입력받는다.
-리턴 값은 int 타입
JOptionPane.showConfirmDialog(parentComponent, message, title, optionType)

  1. parentComponent: 이 창을 띄우는 component를 지정. null이면 전체 화면 중앙에 출력
  2. message: 사용자에게 보여줄 메세지
  3. title : 제목, 다이얼로그 창 문구
  4. optionType: 다이얼로그의 옵션 종류를 지정
    (YES_NO_OPTION, YES_NO_CANCLE_OPTION, OK_CANCLE_OPTION)
//이런식으로 사용합니다.

int answer = JOptionPane.showConfirmDialog(null, "종료하시겠습니까?", "confirm",JOptionPane.YES_NO_OPTION );
if(answer == JOptionPane.YES_OPTION){
	//사용자가 yes를 눌렀을 떄
	System.out.println("프로그램을 종료합니다.");
} else{
	//사용자가 Yes 외 값 입력시
	System.out.println("종료를 취소합니다.");
}


showOptionDialog

사용자가 원하는 선택 버튼을 만들 수 있다.

JOptionPane.showOptionDialog(parentComponent, message, title, optionType, messageType, icon, options, initialValue);

icon : null 지정시 기본값
options : 예, 아니요, 확인, 취소 대신 버튼에 사용자가 원하는 배열을 지정 가능하다.
initialValue : 기본값으로 설정된 것. null 지정시 첫번째 값이 기본이다.

String[] buttons = { "샐러드", "떡볶이", "연어", "쌀국수" };

int num = JOptionPane.showOptionDialog(null, "오늘의 점심", "제목 표시줄입니다.", JOptionPane.YES_NO_CANCEL_OPTION,
		JOptionPane.QUESTION_MESSAGE, null, buttons, "쌀국수");

System.out.println(num);

리턴 값은 int 형이다. 쌀국수 버튼을 누르면 num에 '3'이 값으로 들어가게 되는 것