Rath World Notes by Jang-Ho Hwang

3Nov/09Off

Android UI 개발기: XML 안쓰고 UI 코딩하기

이전 포스트에서 Android로 계산기를 만든다고 했습니다.

그리고 계산기를 만들기 위해 developer.android.com 의 문서들을 정독하기 시작했습니다. Amazon Kindle로 Android Wireless Application Development를 구매하여 읽어보고 있고요. 그런데 생각처럼 쉽지가 않았습니다.

코드로 UI 작성하기가 쉽지 않다.

GUI 개발시 위지윅 에디터를 거의 사용하지 않는 버릇 때문에, 대부분의 UI 개발을 코드만으로 해오고 있었습니다. 복잡한 GUI 만들 때는 코드로 하면 더 어렵지 않느냐 생각하실 수도 있지만 결코 그렇지 않습니다. 복잡도가 높으면 높을수록 코드로 GUI를 뽑아내는 것이 더 높은 생산성을 보입니다. 컴포넌트들을 적절한 범주로 묶어 collection에 넣어 일괄처리할 수도 있고, 화면은 1장이여도 논리적인 기능 단위로 클래스를 분리할 수 있어 편리하기 때문입니다. 예를 들어 계산기를 만든다고 할 때, 버튼이 여러개가 있는데 이것들을 디자이너로 배치하고, 각 아이디를 할당하고 이벤트 핸들러를 붙이는 것은 곤욕입니다. for loop으로 생성하고 화면 resolution에 따라 적절히 컴포넌트의 크기위 위치를 할당하는 것이 개발속도가 더 빠릅니다. UI 생성 코드 로직들을 다 기억한다는 전제하에 유지보수하기도 훨씬 더 편리해집니다. 아주 오랜 시간이 지나, 어떻게 만들었었는지 기억을 거의 못할 때면, 디자이너를 열어서 버튼을 더블클릭하여 어느 핸들러와 연결되어있는지 확인하는 것도 더 편하겠지만, 우리는 문서 작성능력이 있고 기억해야할 것을 어딘가 노트해둘 수 있는 능력을 가진 인간입니다. (게다가 우리에겐 Swing, SWT, JavaFX를 지원하는 MiG Layout이 있습니다. :D)

안드로이드는 UI 생성을 XML 말고도 코드로도 생성할 수 있게 해줍니다. 하지만 그 지원이 생각만큼 높지 않습니다. 문서가 부족하기 때문입니다.

계산기의 현재 숫자를 표현하는 TextView를 만들려고 합니다. 그러면

<TextView
	android:text="1,048,576"
	android:gravity="center_vertical|right"
	android:background="#000000"
        android:textSize="36"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:layout_weight="1"/>

이렇게 만들면 됩니다. UI가 XML로 분리되어 가지는 장점들은

  • 로직과 UI를 파일단위로 분리할 수 있다.
  • 소스코드 변경없이 리소스만 변경하여 UI를 바꿀 수 있다.
  • Portrait/Landscape, 화면 해상도 별, 언어별로 XML 파일을 따로 만들어두고 하나의 로직에 연결하여 사용할 수 있다.
  • 디자이너(위지윅에디터)를 사용할 수 있다.

반면에 동일한 기능을 하는 UI를 코드로 작성해보면

view = new TextView(this);
view.setText("1,048,576");
view.setGravity(Gravity.CENTER_VERTICAL|Gravity.RIGHT);
view.setBackgroundColor(0x000000:
view.setTextSize(36.0f);
view.setLayoutParams(new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f));
  • 로직과 UI는 클래스 단위로 분리할 수 있다.
  • 소스코드 재컴파일, 그저 하면 된다.
  • 수십년동안 많은 프로그래머들이 XML로 분리된 UI 없이도 가변 사이즈를 지원하는 UI를 코드로 작성해왔었고, 다국어 지원을 추가함에도 아무런 문제가 없었다.

코드가 더 복잡해지는 것은 아닙니다.

그러면 왜 코드로 UI 만들기가 어렵다고 했나요?

그 이유는, Android가 XML로 UI 만들기를 권장하고 있기 때문입니다. 코드로 UI 만드는 사람을 위한 친절한 문서가 거의 없기 때문입니다.

위의 TextView 생성 코드를 보시면, 수직 중앙 정렬과 우측 정렬을 하기 위해 android.view.Gravity 의 상수를 가져다 쓰고 있습니다. API 문서에는 setGravity(int)로만 되어 있고, See also 섹션에 Gravity 클래스의 링크가 있습니다. 후다닥 찾기가 애매합니다. XML에서는 그저 android:gravity="center_vertical|right" 라고 입력해주면 되는데 말입니다.

LinearLayout을 쓰고 싶은데, d.android.com 에서 제공하는 문서는 오직 XML 뿐입니다. 위의 코드를 보면 child 컴포넌트에 setLayoutParams(new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f)) 를 실행하여 android:layout_width="fill_parent", android:layout_height="wrap_content", android:layout_weight="0" 과 똑같은 동작을 하도록 했습니다.

가장 큰 어려움은 TextView 클래스에 setLayoutWidth 나 setLayoutHeight, setLayoutWeight 같은 이름을 가진 메서드가 존재하지 않는다는 것입니다. 결국, XML 문서만을 보고 추측하여 쉽게 코드로 옮길 수 없다는 문제가 있습니다.

XML에서 할 수 있는 모든 기능을 API로도 할 수 있습니다. 하지만 쉽게 찾을 수 없는 것이지요.

코드로 UI를 만드는 것이 어렵다고 했는데, 왜 구지 코드로 UI를 만들려고 하나요?

동일한 속성을 가지는 컴포넌트를 여러개 만들려고 할 때, XML 에서는 copy and paste가 불가피합니다. 계산기 앱의 경우 버튼이 4x4로 16개가 있습니다. 버튼의 배경색을 검정색에서 회색으로 바꾸고자 한다면 16번 손을 움직여야 합니다. 코드로 하면 루프 몇 번 돌아서 해결할 수 있는데 말입니다.

 1   private void createButtons() 
 2   {
 3     for(int i=0; i<nums.length; i++)
 4     {
 5       final int number = i;
 6       nums[i] = new Button(getContext());
 7       nums[i].setText(String.valueOf(number));
 8       nums[i].setGravity(gravity);
 9       nums[i].setTextSize(textSize);
10       nums[i].setOnClickListener(new View.OnClickListener() {        
11       @Override
12       public void onClick(View v) {
13         action.processNumber(number);
14       }
15     });
16     }
17             
18     for(final Operator op : Operator.values()) 
19     {      
20       Button button = new Button(getContext());
21       button.setText(op.text());
22       button.setGravity(gravity);
23       button.setTextSize(textSize);
24       button.setOnClickListener(new View.OnClickListener() {
25       @Override
26       public void onClick(View v) {
27         action.processOperator(op);
28       }        
29       });        
30       operatorButtons.put(op, button);
31     }
32   }

이렇게..  안드로이드 계산기가 만들어져가고 있습니다.

Posted by Jang-Ho Hwang

Tagged as: , , , Comments Off
Comments (22) Trackbacks (0)
  1. ui를 소스로 코딩하는 장점과 xml로 했을때의 장점이 분명이 존재합니다.
    All 소스 또는 All xml로 개발한다는것도 효율성에서 보면 분명 문제가 있다고 봅니다.
    앱을 개발하다보면 여기저기 찍어내야할 부분이 생기죠! 그런 부분들을 모듈화해야할때 적시적소에 잘 사용할 수 있도록 개발하는게 좋지 않을까 생각됩니다.

  2. 기본틀은 xml 에서 잡고 동적으로 처리할때 코드로 하는게 맞지않나싶네요.. 개인차가있긴하지만

  3. 늦깎이 안드로이드 입문자입니다. 저도 UI는 코드로 찍어내자 주의입니다. 오히려 xml이 더 편리하다라고 하는 분들도 있는데 전 그렇게 생각하지 않습니다. _-_ 어떻게 하면 UI를 코드로 찍어내는 것이 더 월등하다고 할 수 있을까 … 안드로이드에서의 XML은 initialization phase에서만 사용하고 웬만하면 사용하지 못하게 할까 … 를 찾던 중에 제가 토해내고 싶은 온갖 불만이 쌓인 이 글을 찾았네요. awesome 입니다 awesome!!

  4. 리소스가 부족한 경우는 코드로 UI를 짜는것도 나쁘다고 할 순 없겠지만,
    기본적으로는 어플리케이션의 성능을 위해서 XML로 UI를 만드는게 좋다고 합니다.

    LinearLayout 사용하면서 하면, 그렇게 오래걸리지도 않더라구요 ㅋ
    id만 알아보기 좋게 잘 지정해주면, 요것도 편하게 쓸 수 있습니다.

  5. 문서에도 xml view inflate 비용이 크다고 나와있는데 실행시 성능이 좋아진다는 말은 이해하기 어렵네요.

  6. 하지만 그건 그떄고… 리소스 만땅 부족할때….
    요즘은 머신이 어느정도 받혀 줘서 그런지… 소스로 코딩하는게 더 빠릅니다.

    늦을수도 있지만…..

  7. 저도 프로그램을 UI보다 코딩으로 하는것을 선호 해왔는데…..

    안드로이드는 권장 사항이 XML인 이유가 실행시 성능이더군요

    각 화면마다 모두 프로그램의 변경으로 바꿔가면서 처리하는것은 프로그램머에게는 괞찮지만…

    머신은 짜증나는가 봅니다…

    http://www.androidside.com/docs/docs1.5/guide/practices/design/performance.html

    읽어 보셔도 아시겠지만 변수 자체부터 두드러기가 나는가 봅니다.

  8. 좋은 글 잘봤습니다. 현재 나오는 안드로이드 폰 같은 경우는 xml 을 이용하나 소스코딩을 이용하나 퍼포먼스나 메모리 문제가 별차이가 없다고만 설명이 되어있는데 이차이점을 설명해 주는 사이트는 없는건가요??ㅠㅠ 찾기가 쉽지 않군요 저도 UI 소스코딩을 하는 쪽으로 생각하고 있는데 이부분도 찾기가 쉽지 않군요..
    혹시 제질문에 대한 답이 있으시면 멜로 좀 부탁드려도 될까요??
    이미지 폴더를 만들어서 이미지를 불러서 사용할려고 하는데 가능할지요~~

  9. 글 잘봤습니다.^^

    좋은 내용 감사합니다.

    UI 소스코딩을 함으로써 인해 메모리나 퍼포먼스적인 측면에서 유리한가요??

    그리고 윈도우처럼 이미지폴더를 생성 하고 거기서 이미지를 불러다 쓰는 방법을 알고 계시는지요

    이런 내용 포스팅 가능하신가요?? 사이트를 뒤지면서 찾고 있는데 생각보다 찾기 쉽지 않네요.

    가능하시다면 메일로도 좀 부탁드립니다. 너무 질문만 하고 가네요.

    감사합니다.

  10. 감사합니다. 글 잘봤습니다. 큰 도움 되었습니다.

  11. 흠.. 색상을 바꾸고 싶다면 스타일을 지정해서 사용하시면 유지 보수하는데 편리하지않을까요??

    xml이라고 불편한것만 같지는 않네요 ㅎㅎ

  12. 정말 Android sdk 2 되면서 에뮬레이터든 디바이스든 부팅 속도 장난 아니게 느려졌어요 ㅎㅎ 영록님 말씀대로 프로그램적인 부분을 제외한 스타일적인 부분의 테스트 효율성을 위해서는 XML 활용하는 장점도 있는 것 같아요. (레스님 블로그에 댓글 첨 다는듯 🙂

  13. 레이아웃 관련 속성은 LayoutParams라는 클래스를 만들고 setLayoutParams로 넣어주면 됨. 하나 골치아픈 것은 LayoutParams의 클래스를 부모 레이아웃에 맞게 골라줘야 한다는.

    근데 사실 스타일 중복은 Style과 Theme라는 게 있어서 어느 정도 해결이 가능하기 때문에 동적으로 추가되어야 하는 컴포넌트가 아니라면 중복 문제는 그리 크지 않다는. 나도 달력 만들 때 달력의 날짜 셀들은 XML로 쭉 copy&paste로 넣고 숫자 집어넣는 것만 for로 돌리는데 그러면 로직과 뷰가 잘 분리되서 코드 양도 줄고 가독성도 좋은 듯.

    XML에 이벤트 리스너를 지정할 수 없는 것은 코딩 스타일에 따라 별로 불편하지 않을 수도. MVC 모델에서 XML을 뷰로 쓰고 Activity나 POJO를 컨트롤러로 쓴다면 컨트롤러에서 이벤트 리스너 등록을 하기 때문에 어차피 필요한 코드들은 잘 모여 있어서 별로 문제가 안된다는…

    뭐 사실 안드로이드 레이아웃 디자이너는 개판이라서 위지윅의 장점을 별로 살릴 수 없긴 하지만, 안드로이드 에뮬레이터가 워낙 느려서 바로바로 결과를 볼 수 있는 XML이 좀더 생산성이 높은 듯.

  14. @오스카
    그렇죠? 헤헤 동감합니다.

  15. UI 제작에서 위지윅은 어디까지나 디자인 레벨에서 훌륭한 도구이고, 개발자에겐 역시 코딩이… -0-

  16. @jong10
    getAttribute로 가져온 값에서 괄호와 그 안의 값들도 함께 파싱하도록 하면 파라미터 전달까지 할 수 있겠군요. 좋은 아이디어 감사합니다. 나중에 XML로 UI 구성해보게 되면 꼭 써봐야겠습니다. 😀

  17. 파라미터 전달까지는 안되서, 효용은 좀 떨어지지만요=3=3 (그나저나, final을 저렇게 쓸 수 있군요. +_+ 전 바보같이 for문 돌리면서 리스너 달 때에는 생성자에 써버릇 했는데…)

  18. 저희팀에선 그래서, mxml의 onClick 비슷한 식으로, 메소드 이름을 xml 안에 적어주면, 리플렉션으로 찾아가는 커스텀 클래스를 만들어서 쓰고 있어요;;; 상속 받아서 클래스 만들고, 생성자에서 attrs.getAttribute*() 로 태그에 있는 값을 가져올 수 있더라구요.

  19. @endloop
    설명이 필요한 부분 있으면 말씀해주세요. 해당 주제로 새로운 포스트를 작성토록 하겠습니다.

  20. 봉사 문 꼬리 잡는 중…

  21. @백가
    ADT 디자이너에서 XSL를 지원해주면 좋겠네요. 헤헤
    XSL을 많이 안써서.. 위의 코드에서 했던 것 처럼 컴포넌트 Id에 array를 넣고 그것을 코드에서 뽑아 쓸 수 있는지도 애매하고요.

    무엇보다 불만인 것은, XML UI에 바로 이벤트 리스너를 명시할 수 없다는 점이에요. Flex의 MXML처럼 onclick 같은 것을 구현하려면 지금 구조에서는 답이 안나와서 ^^;

  22. loop라.. xsl 까지 동원하는건 쫌 그렇겠지? ^^


Trackbacks are disabled.