1. AlertDialog

AlertDialog는 기본적인 Text부터 별도의 복잡한 View까지를 별도의 modal dialog에 담아 사용자에게 notify하는데 사용된다.

Toast와 는 다르게 AlertDialog는 사용자가 하던 작업으로부터 focus를 빼앗아 사용자가 하던 작업을 방해 하기 때문에 사용자에게 반드시 알려야 할 중요한 메시지가 있을때만 사용하는 것이 좋다. (그래서 이름도 Alert 이다)

예를 들어, '배터리가 크리티컬하게 낮다는' broadcast를 접수하고 사용자에게 진행하던 작업을 저장/마무리하도록 경고하는 용도 등이 있을수 있다. 

 

 

 

다음은 AlertDialog의 상속 구조이다.

 

 

 

AlertDialog의 구성

AlertDialog는 다음의 요소들을 조합해 구성한다.

  • icon
  • title
  • message / AlertDialog 자체 제공 List 중 택1: 동시에 표현 불가능
  • 커스텀view: 밑에서는 ListView를 사용 했지만 어떤 것이라도 표현 할 수 있음
  • button: 0~3개 까지 가능

 

2번 화면을 보면 메시지가 없는데, 이는AlertDialog에서 제공하는 list와 message를 동시에 사용할 수 없기 때문이다.

즉, setMessage(), setItem() 메소드는 같이 사용할 수 없다. 둘을 동시에 표현하려고 하면 둘 다 이상하게 출력된다.

 

위의 화면들은 어디까지나 하나의 AlertDialog안에 표시 할 수 있는 구성요소를 나타낸는 것임으로

필요에 따라 적절히 넣고 싶은 것을 넣고 빼고 싶은 것을 빼서 AlertDialog화면을 구성하면 된다.

 

 

 

AlertDialog의 생성

AlertDialog는 항상 AlertDialog의 내부 객체인 AlertDialog.Builder 객체를 사용해 생성/설정 한다.

AlertDialog의 생성자 3개가 모두 protected 임으로 일반적인 방법으론(new 이용) 생성하고 싶어도 할 수가 없다.

 

일반적으로 AlertDialog.Builder 객체가 제공하는 여러 메소드들을 이용하여 객체 생성 전에 생성에 필요한 정보를 전달한 후 AlertDialog.Builder:create() 메소드(또는 show() 메소드)를 최종 사용해 AlertDialog객체를 생성한다.


이미 생성된 AlertDialog 객체를 설정(icon, 타이틀, 버튼 등)하는 것은 AlertDialog클래스가 제공하는 여러 가지 메소드를 이용한다.

 

메소드 chaining을 통해 AlertDialog생성 전 설정을 편하게 하기 위해 AlertDialog.Builder 클래스의

create(), show() 제외 한 거의 모든 메소드는 AlertDialog.Builder객체를 리턴한다.

(create(), show() 메소드는 AlertDialog객체 리턴)

 

생성 예는 다음과 같다.

AlertDialog.Builder객체와 method chaining을 통한 AlertDialog 객체 생성 예

소스 펼치기

 

 

Dialog 생성 시 참고할 점

AlertDialog는 Dialog에서 상속함으로 다음에 언급하는 Dialog 생성 시 참고할 사항 역시 AlertDialog에도 적용된다.

 

첫째, 모든 dialog 생성 루틴은 Activity:showDialog(int) 메소드의 callback인 Activity:onCreateDialog(int)를 오버라이딩하여 그 내부에서 구현하는 것이 좋다. 그 이유는 다음과 같다.

  • Activity:onCreateDialog(int)내부에서 생성되는 dialog는 부모 Activity()로부터 중요한 객체들을 상속 받는다. (예를 들면, 부모 activity가 사용하는 메뉴, 오디오 스트림의 볼륨 객체 등등)
  • Activity:onCreateDialog(int)내부에서 생성된 dialog는 부모 activity에 의해 자동으로 그 이력이 관리 된다. 그래서 dialog의 특정 속성 값을 변경한 후 특별한 저장 절차 없이dialog를 닫았다 하더라도 dialog의 상태가 부모 activity에 의해 자동으로 보관되어 있음으로 다시 dialog를 화면으로 불러올 때 기존 설정이 그대로 다시 표현 되는 것을 볼 수 있다.

 

Activity:onCreateDialog(int)외부에서 만들어진 Dialog 객체는 그 이력이 관리 되지 않으며, activity와 연결 하고 싶다면 Dialog.setOwnerActivity(Activity)를 사용한다.

 

또, Activity:onCreateDialog에서 Dialog객체를 생성하는 것은 재사용이 필요한 dialog의 경우 유용하지만 그렇지 않은 단발성 dialog의 구현에는 적합하지 않다. 그럼으로 간단한 경고 메시지 정도를 표현 할 용도의 dialog라면 아무 곳에서나 생성하여도 상관없을 것이다.

 

 

둘째, Activity:onCreateDialog(int)내부에서 생성된 dialog를 사용 후 닫았다 다시 화면에 표시할 때(Activity:showDialog(int)의 재호출)는 Activity:onCreateDialog(int)가 다시 실행 되지 않는다. 말했듯이 부모 activity는 한번 생성된 dialog 객체를 관리 하기 때문에 재 생성이 필요 없기 때문이다. 그래서 dialog가 화면에 보여지기 전에 dialog의 속성을 어떤 값으로 변경하고 싶다면 dialog가 화면에 표시될때 마다 항상 호출되는 Activity:onPrepareDialog(int) callback을 오버라이딩하여 그 내부에 속성 변경 루틴을 구현 하여야 한다.

 

 

셋째, Activity:onCreateDialog(int)내부에서 생성된 dialog객체는 Activity:removeDialog(int)가 호출되기 전까지 그 이력이 부모 activity에 의해 관리 된다. 그럼으로 오버헤드를 줄이기 위해 재 사용이 필요 없는 dialog객체는 Activity:removeDialog(int)를 사용해 그때그때 정리 해 주는 것이 좋다.

 

 

넷째, Activity A에서 가상키보드를 이용해서 text입력 중 예상치 않은 Dialog 객체 B가 popup하였다고 가정해 보자. 이런 경우 기본적으로 안드로이드는 무조건 사용자가 activity A에서 사용하던 가상키보드를 시스템 자원으로 환원해 버린다.

왜냐하면 가상키보드 객체는 시스템에서 하나의 인스턴스 생성만 허락 함으로 popup된 dialog B에 edit 가능한 위젯이 있어 사용자가 키 입력을 하고자 할 때 시스템은 가상 키보드 자원을 B에게 제공 하여야 하기 때문이다. 이는 위의 그림과 같이 popup된 B에 edit가능한 위젯이 없을 경우에는 매우 비효율적이면서 불편하기까지 하다. B는 가상키보드 자원을 절대로 요구 하지 않지만 시스템은 이에 대비하기 때문에 비효율적이고, 사용자가 popup된 dialog를 닫았을 때 사용하던 가상키보드가 없어져서 다시 가상키보드를 불러와야 하기 때문에 불편하다.

 


그래서 생성된 Dialog객체에 가상키보드를 사용하는 구성요소가 없다면 Dialog 객체가 화면에 보여지기 전에 (ex. Activity:onPrepareDialog(int) 메소드 같은 곳에서) 다음과 같은 코드를 삽입하여 dialog가 절대로 가상키보드(IM)를 요청할 수 없게끔 설정하여야 한다.

Dialog객체.getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,

            WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);



 

하지만, AlertDialog객체의 경우 이런 일련의 작업이 자동화 되어있다. (물론 override 시킬 수도 있다) AlertDialog 객체 C가 있다고 하자, C는 생성 후 화면에 표시되기 전에 자신의 구성요소 중 글자 입력이 가능한 view(ex. EditText 위젯 등)가 존재하는지 확인 한다. (자신의 모든 구성요소를 상대로 View.onCheckIsTextEditor()를 호출하고 리턴값 true/false를 검사 함) 만약 AlertDialog 객체 구성요소 중에 글자 입력 가능한 view가 없다면, 자동으로 위의 setFlags() 메소드를 자기 자신에게 적용하기 때문에 popup이 화면에 표시될 때 activity A는 사용하던 가상키보드 자원을 반납할 필요가 없어진다. 반면 글자 입력 가능한 view가 있다면 안드로이드는 A로부터 가상키보드 자원을 회수하여 C가 사용할 수 있도록 준비 할 것이다.

 

사실 지금까지는 설명의 편의를 위해 가상키보드로 설명했지만 위의 내용은 트랙볼 등의 모든 Input Method(IM)에 통용된다.

 


 

다음은 지금까지 설명한 것을 바탕으로 구현해본 AlertDialog예제이다.

 

AlertDialog 예제 (main.xml)

소스 펼치기

 

 

AlertDialog 예제 (MyAlertDialog.java)

소스 펼치기

 

 

다음은 실행 화면이다.

두 번째 버튼으로 화면에 나타나는 AlertDialog의 경우 한번 지정된 속성(radio 버튼 선택)값은 dialog가 닫혔다 다시 표시되어도 그대로 유지 되는 것을 볼 수 있다. 이는 AlertDialog가 onCreateDialog(int) callback 내부에서 생성되고, 그 이력이 MyAlertDialog 객체에 의해 관리 되기 때문이다.

 

 

 

 

 

 

저작자 표시 비영리 변경 금지
신고
Posted by 무한만족 i티거