저작자 : The Art of Readable Code by Dustin Boswell and Trevor Foucher. Copyright 2012 Dustin Boswell and Trevor Foucher, 978-0-596-80229-5
번역본 : 읽기 좋은 코드가 좋은 코드다. / 한빛미디어

4. 미학

자신의 코드를 일관성 있게, 의미 있는 방식으로 '정렬'하여, 읽기 더 편하고 빠르게 만들 수 있다.

  • 여러 블록에 담긴 코드가 모두 비슷한 일을 수행하면, 실루엣이 동일해 보이게 만들어라.
  • 메소드를 활용하여 불규칙성을 정리하라.
  • 코드 곳곳을 '열'로 만들어서 줄을 맞추면 코드를 한 눈에 훑어보기 편하다.
  • 코드의 한 곳에서 A, B, C가 이 순서대로 언급되고 있으면, 다른 곳에서 B, C, A와 같은 식으로 언급하지 말라. 의미 있는 순서를 정하여 모든 곳에서 그 순서를 지켜라.
  • 빈 줄을 이용하여 커다란 블록을 논리적인 '문단'으로 나누어라
  • 일관성 있는 스타일은 '올바른' 스타일보다 더 중요하다.
Posted by outliers
,

저작자 : The Art of Readable Code by Dustin Boswell and Trevor Foucher. Copyright 2012 Dustin Boswell and Trevor Foucher, 978-0-596-80229-5
번역본 : 읽기 좋은 코드가 좋은 코드다. / 한빛미디어

1. 코드는 이해하기 쉬어야 한다.

- 코드는 다른 사람이 그것을 이해하는 데 들이는 시간을 최소화하는 방식으로 작성되어야 한다.

Part One - 표면적 수준에서의 개선

2. 이름에 정보담기

  • 특정한 단어 고르기
  • 보편적인 이름 피하기 (혹은 언제 그런 이름을 사용해야 하는지 깨닫기).
  • 추상적인 이름 대신 구체적인 이름 사용하기.
  • 접두사 혹은 접미사로 이름에 추가적인 정보 덧붙이기.
  • 이름이 얼마나 길어져도 좋은지 결정하기
  • 추가적인 정보를 담을 수 있게 이름 구성하기

2.1 특정한 단어 고르기

이름에 정보를 담아내는 방법 중 하나는 매우 구체적인 단어를 선택하여 무의미한 단어를 피하는 것이다.

예) def GetPage(url) -> FetchPage() 혹은 DownloadPage()
     class BinaryTree { int size() ... } -> Height(), NumNode(), MemoryBytes()
     class Thread { void Stop() ...} -> Kill()

단어 

대안 

 send

 deliver, dispatch, announce, distribute, route 
 find  search, extract, locate, recover
 start  launch, create, begin, open
 make

 create, set up, build, generate, compose, add, new

재치있는 이름보다 명확하고 간결한 이름이 더 좋다

2.2 tmp나 retval 같은 보편적인 이름 피하기

  • 이름에 정보를 담아내는 방법 중 하나는 매우 구체적인 단어를 선택하여 무의미한 단어를 피하는 것이다.
  • retval 이라는 이름은 정보를 제대로 담고 있지 않다. 대신 변수값을 설명하는 이름을 사용하라.
  • tmp라는 이름은 대상이 짧게 임시적으로만 존재하고, 임시적 존재 자체가 변수의 가장 중요한 용도일 때에 한해서 사용해야 한다.
  • 루프반복자를 다른 목적으로 사용하면 혼돈을 초래할 수 있다. 그렇게 하지 말자!!
  • tmp, it, retval 같은 보편적인 이름을 사용하려면, 꼭 그렇게 해야 하는 이유가 있어야 한다.

2.3 추상적인 이름보다 구체적인 이름을 선호하라.

변수나 함수 혹은 다른 요소에 이름을 붙일 때, 추상적인 방식이 아니라 구체적인 방식으로 묘사하라.

2.4 추가적인 정보를 이름에 추가하기.

변수나 함수 혹은 다른 요소에 이름을 붙일 때, 추상적인 방식이 아니라 구체적인 방식으로 묘사하라.

ex) string id; -> hex_id;
     var start; -> var start_ms;

다음 표는 단위를 포함하지 않는 함수의 인수와 단위를 포함하는 더 나은 함수의 인수를 나타내고 있다.

 함수 

 인수 단위를 포함하게 재작성 

 Start(int delay) 

 delay -> delay_secs 

 CreateCache(int size) 

 size -> size_mb 

 ThrottleDownload(float limit) 

 limit -> max_kbps 

 Rotate(float angle) 

 angle ->degress_cw 

 

다음 표는 이름에 추가적인 정보를 나타내야 하는 여러 가지 상황을 보여준다.

 상황 

 변수명 

 더 나은 이름 

 패스워드가 plaintext 에 담겨 있고, 추가적인 처리를 하기 전에 반드시 암호화되어야 한다.

 password 

 plaintext_password 

 사용자에게 보여지는 설명문이 화면에 나타나기 전에 이스케이프 처리가 되어야 한다.

 comment   unescaped_comment 
 html의 바이트가 UTF-8으로 변환되었다.

 html 

 html_utf8 

 입력데이터가 url encoded 되었다. 

 data 

 data_urlenc 

변수의 의미를 제대로 이해하는 것이 중요하다면 그 의미를 드러내는 정보를 변수의 이름에 포함시켜야 한다.

2.5 이름은 얼마나 길어야 하는가?

  • 좁은 범위에서는 짧은 이름이 괜찮다.
  • 긴 이름 입력하기 - 더 이상 문제가 되지 않는다.(단어 완성 기능 사용 : 이클립스 -> alt-/)
  • 약어와 축약형
    팀에 새로 합류한 사람이 이름이 의미하는 바를 이해할 수 있다면 축약형을 사용하고 그러지 않다면 사용하지 말라
  • 불필요한 단어 제거하기
    ex) ConvertToString() -> ToString(), DoServeLoop() -> ServeLoop()

2.6 이름 포맷팅으로 의미를 전달하라. 상수, 멤버변수, 지역변수 등 포맷팅을 다르게 사용하라

 

요약

  • 특정 단어를 사용하라 - 예를 들어 상황에 따라 Get 대신 Fetch나 Download를 사용하는 것이 더 나을 수 있다.
  • 꼭 그래야 하는 이유가 없다면 tmp나 retval과 같은 보편적인 이름의 사용을 피하라.
  • 대상을 자세히 묘사하는 구체적인 이름을 이용하라 - ServerCanStart()는 CanListenOnPort()에 비해서 의미가 모호하다.
  • 변수명에 중요한 세부 정보를 덧붙여라 - 예를 들어 밀리초의 값을 저장하는 변수 뒤에 _ms를 붙이거나 이스케이핑을 수행하는 변수의 앞에 raw_를 붙이는 것이다.
  • 사용 범위가 넓으면 긴 이름을 사용하라 - 여러 페이지에 걸쳐서 사용되는 변수의 이름을 하나 혹은 두 개의 짧은 문자로 구성해 의미를 알아보기 힘들게 짖지 말라. 다만 적은 분량(좁은 범위)에서 잠깐 사용되는 변수명은 짦을수록 더 좋다.
  • 대문자나 밑줄 등을 의미 있는 방식으로 활용하라 - 예를 들어 클래스 멤버를 로컬 변수와 구분하기 위해서 뒤에 '_'를 붙일 수 있다.

 

 

Posted by outliers
,

참고링크 : http://www.androidpub.com/2207296

 

단순 번역이 아니라, 필요없는 부분(내가 생갈할 때, 굳이 언급안 해도 되는 부분)은 과감히 삭제하였으며, 이해를 돕기 위해 필요한 부분은 덧 붙이기도 했습니다.


Multiple-Screen 관련 이슈 가지고 계신 분들께 큰 힘이 되길 바랍니다.


=======================================================================


Supporting Multiple Screens


안드로이드는 서로 다른 screen size 및 density 를 갖는 device 에서 구동됩니다.

안드로이드 system 은 application 을 위해, 이런 특성을 care 할 수 있도록 개발 환경을 제공 하며, 대부분 device 의 screen UI 에 적용할 수 있는 feature 를 가지고 있습니다.

또한, 특정 screen size 및 density 에 맞게 조절할 수 있도록,(서로 다른 screen configuration 에 맞게 UI design을 최적화할 수 있도록) API 도 제공해 줍니다.


안드로이드 자체가 App 을 서로 다른 screen 에 맞게 scaling 및 resizing 을 수행해주지만, 각각의 device screen size 및 density 에 맞게 application을 최적화시켜주는 건 당신(개발자) 몫입니다.

그렇게 함으로써, user experience를 극대화 시킬 수 있으며, 사용자들은 당신의 app 이 그들의 device 에 맞게 design 되었다고 느끼게 될 것입니다.


이 문서 내용을 익힘으로써, 당신은 하나의 apk 로 모든 android supported screen configurations 에서 정확하게 동작하는 application 을 개발할 수 있습니다.


Overview of Screens Support

Terms and concepts


Screen size
- 물리적인 화면 크기

Screen density
- 물리적인 크기 안의 pixel 개수. 즉, pixel 밀도라고 보면 됩니다.
크기가 클 수록 pixel 밀집도가 올라가므로 선명하게 보이겠죠?

Orientation
- Landscape or Portrait (가로/세로 뷰)

Resolution (해상도)
- screen 의 총 pixel 개수.가로/세로 표시함으로써 총 pixel 개수를 알 수 있다.

Density-independent Pixel (dp)
- 절대 길이를 표시해 주는 단의.
- 160 dpi 에서의 1 pixel 길이는 1 dp 와 동일하다.

Range of screens supported

Android 1.6(API Level 4) 부터, 안드로이드는 Multiple screen sizes, densities 에 대한 지원기능을 제공해 왔습니다. 이러한 안드로이드 시스템의 feature 를 사용함으로써, 각 screen configurations 에 맞게 UI 최적화할 수 있으며, 각 screen 에 맞는 최고의 user experience 를 제공해줄 수 있습니다.
당신이 multiple screens 를 위한 UI 설계하기 위한 방법을 단순화시키기 위해, 안드로이드는 screen configuration 을 다음과 같은 range로 나누어서 관리합니다.
(수 많은 device screen 의 각각의 특성에 따라서 일일히 대응하기는 불가능하겠죠.)

- A set of four generalized sizes : small, normal, large, and xlarge
- A set of four generalized densities: ldpi(low), mdpi(medium), hdpi(high), and xhdpi(extra high)

이들은 Normal size and mdpi (HVGA)를 기준으로 arranged 되었으며, 이 기준은 최초의 android powered device 인 T-Mobile G1 의 screen configuration 이었다.
이 device 는 HVGA screen 이었으며 이는 Android 1.6 까지 android 가 지원하는 유일한 screen configuration 이었다.

Device 마다 각 size 와 denisty 는 조금씩 미세하게 다를 수 있다. 예를 들면, 동일한 screen size 를 가진다는 서로 다른 device 도 실제로는 약각 size 또는 가로/세로 비율(ratio)이 다를 수 있다는 것이다.
density 도 마찬가지로 pixel 밀도가 약간씩 다를 수 있다.
안드로이드는 이런 미묘한(미세한) 차이점들을 간단하게 추상화시킴으로, 이로 인해 당신은 generalized size 와 generalized density 만을 위해 UI design 을 하고, 나머지는 system 이 최종 적용하도록 하도록 하면 된다.

Figure 1. Illustration of how Android roughly maps actual sizes and densities to generalized sizes and densities (figures are not exact).


위에 표시된 각 generalized size 들은 각 특성에 맞게 최소한의 해상도 값을 갖게 된다.

  • xlarge screens are at least 960dp x 720dp
  • large screens are at least 640dp x 480dp
  • normal screens are at least 470dp x 320dp
  • small screens are at least 426dp x 320dp

  • 당신은 서로 다른 화면 사이즈와 density 에 대한 Application 의 UI 를 최적화하기 위해, 각 generalized sizes and density 에 맞는 resource 를 제공해 주면 된다.

    예를 들면, 당신은 각 screen size 에 맞는 각각의 레이아웃을 만들 수 있으며, run time 때에 시스템은 현 실행되는 device 의 화면 설정값에 따라서 적당한 resource 를 사용할 수 있을 것이다.


    당신은 모든 screen size 와 density 조합을 갖는 각 screen 을 위한 resource 를 제공할 필요는 없다.

    안드로이드 시스템은 당신의 Application을 각 device screen의 configuration 값에 따라서 rendering 하는 강력한 호환성을 제공해준다.(당신이 이 문서에 명시된 practice 데로 구현할 경우에 한한다.)


    Density independence

    당신 App 이 각 device 의 density 에 상관없이, 동일한 element size 를 유지하고 있다면, 당신 App 은 "Density independence" 특성을 가지고 있는 것이다.

    Density independence 를 유지한다는 것은 매우 중요하다. 왜냐하면, 그것 없이는 UI element size 가 low density 에서는 크게 보이며, high density 에서는 더 작게 보이기 때문이다.
    Application 의 element들이 screen density 에 따라 size 가 달라진다면, 사용성에서 큰 문제를 야기할 수 있다.

    Figure 2. Example application without support for different densities, as shown on low, medium, and high density screens.

    Figure 3. Example application with good support for different densities (it's density independent), as shown on low, medium, and high density screens.


    안드로이드 시스템은 이를 위해 두 개의 방법을 제공해준다.

    - 시스템은 현 device density 에 맞게 dp units 을 적절히 scale(확대/늘리다.) 해준다.

    - 시스템은 현 device density 에 맞게 drawble resources 들을 scale 해준다.


    Figure 2 의 경우, Text view 와 Bitmap drawble 은 px units 으로 명시되어 있으며, 그래서 screen density 에 따라서 그 크기가 달리 보인다. 이는 screen size 는 같을지라도, high density 스크린의 경우, 인치당 pixel 수가 더 많기 때문이다.

    Figure 3 의 경우, dp units 으로 명시되었다. medium denisty 의 경우, Figure 2 와 동일하게 보이지만, low/high density 에서는 screen 에 맞게 상대적으로 scale up/down 해주므로 결국medium density 와 동일하게 보인다.


    대부분의 경우, dp units 명시와 "wrap_content" 의 사용만으로, 시스템은 현 screen density 의 scaling factor 에 따라서 bitmap drawables 을 적절하게 scaling up/down 해 주며, 이로 인해서 Application 의 density independence 를 보장할 수 있게 된다.


    하지만, bitmap scaling 은, 위 화면에서 알아챌 수도 있겠지만, 흐릿하게 보이거나 부분 부분 보이도록 하는 결과가 나올 수 있다.

    이러한 문제를 피하기 위해서는 당신은 각각의 density 에 맞는 resource 를 제공해 줄 필요가 있다.

    예를 들면, high-density screens 을 위해 higher-resolution bitmap 을 제공한다면, 시스템은 default(medium-density) resource 를 resizing 하는 것 대신에 제공된 resource 를 사용하게 될 것이다.

    다음 장에서는 이런 방법에 대해 좀 더 살펴보겠다.


    How to Support Multiple Screens

    안드로이드의 '멀티플 스크린 지원하기'의 기본은 현 스크린 정보에 맞게 적절한 방법으로 어플리케이션의 layout 과 bitmap drawables 를 렌더링하는 기법에 대한 것이다.
    시스템은 스크린 사이즈와 Density 에 맞게 Layout 을 scaling 하고, Bitmap drawables 은 스크린 Density 에 맞게 적절하게 scaling 한다.
    하지만, 각 스크린 사이즈에 맞게, 좀 더 완벽하게 대응하기 위해서는 당신은 하기 항목들을 수행해야 한다.

    - manifest 파일안에 지원하는 스크린 사이즈 선언하기
    지원하는 스크린 사이즈를 선언해 놓음으로써, 오직 지원가능한 스크린 사이즈를 가진 해당 Device 에서만 당신의 App.을 다운로드가 가능하도록 하는 방법이다.

    - 각각의 스크린 사이즈에 맞는 각각의 Layout 작성하기.
    물론, 안드로이드가 당신의 App.을 스크린 사이즈에 맞게 resize 해주지만, 상황에 따라서는 스크린 사이즈별 레이아웃이 필요할 수 있다. 예를 들면, 좀 더 큰 스크린일 경우, 남아도는 여백의 스크린 공간을 활용하기 위해, 당신은 elements 의 position 이나 size 를 변경할 필요성을 느낄 것이다.
    이를 위한 size-specific 한 resource 를 명시해 주는 qualifiers 는 small, normal, large 그리고 xlarge 이다. 예를 들면 xlarge screen 을 위한 layout 은 "layout-xlarge" 폴더안에 넣어두면 된다.

    하지만,~~ Anroid 3.2(API Level 13) 에 와서 위의 size groups 들은 사용하지 않으며, 대신, sw<N>dp 형식의 qualifiers 로 명시해 준다. 예를 들어 당신의 multi-pane tablet layout 이 적어도 600 dp screen width 을 가져야 한다면 해당 layout resource 는 "layout-sw600dp" 폴더안에 넣어 두면 된다.

    - 각각의 스크린 Density 에 맞는 Bitmap drawables 제공하기.
    안드로이드는 기본적으로 각 스크린 사이즈에 맞추기 위해 당신의 bitmap drawables (.png, .jpg and .gif files) 과 Nine-Patch drawables (.9.png files) scaling 한다.
    예를 들면, 당신이 bitmap 파일을 medium screen density (mdpi) 용으로만 제공한다면 시스템은 알아서 hdpi 또는 ldpi device screen 에 맞게 scale up/down 해준다.

    Density-specific resources를 위해 명시해주는 qualifier 는 ldpi(low), mdpi(medium), hdpi(high), 그리고 xhdpi (extra high) 이다.
    예를 들어 high-density 용으로 제작된 bitmap 파일은 "drawable-hdpi" 폴더에 넣어주면 된다.

    Runtime 에, 시스템은 아래의 과정으로 가능한한 최적의 display 를 보장해준다.

    1. 시스템은 적절한 대체 resource 를 사용한다.
    스크린 사이즈와 Density 에 맞게 시스템은 당신의 App 에서 필요한 qualifier 가 붙은 폴더를 찾아 해당 폴더내에 있는 resource 를 사용할 것이다.

    2. 만약 매칭되는 resource 가 없다면, default resource(mdpi) 를 사용하며, 이를 스크린 사이즈와 Density 에 맞게 scale up/down 한다.
    default resource 란, tag(qualifier) 가 붙지 않은 폴더내에 존재하는 resource 를 말한다.(layout or drawable)
    시스템은 이를 기준 size 와 density 로 가정하고 각각의 스크린 configuration 에 맞게 scale up/down 한다. 그렇다고 항상 default 폴더에서 가져오는 것은 아니다. 경우에 따라서는 좀 더 좋은 결과를 얻기 위해, 다른 폴더에서 resource 를 가져오는 경우가 있다.
    예를 들면, 시스템이 ldpi 용 resource 를 찾고 있는데, 이게 없다면, hdpi resource 를 scale down 할 것이다. hdpi resource 에서 ldpi 로 factor 0.5 값으로 scale down 하기 좀 더 쉽고, 결함없이 가능하기 때문이다. mdpi resource 에서 ldpi 로 scale down 할 경우, factor 값은 0.75 가 된다.

    Using configuration qualifiers


    안드로이드는 시스템이 현 스크린 특성에 맞게 적절한 resource 를 선택할 수 있도록 여러개의 Configuration Qualifiers 를 제공해 준다.

    Configuration Qualifiers 는 resource directory name 에 덧 붙일 수 있도록 string 으로 표시되며 이 값으로 어떤 resource 들이 해당 폴더안에 들어있는지 파악할 수 있게 된다.


    Table 1. Configuration qualifiers that allow you to provide special resources for different screen configurations.

    Screen characteristic Qualifier Description
    Size small            Resources for small size screens.
    normal Resources for normal size screens. (This is the baseline size.)
    large Resources for large size screens.
    xlarge Resources for extra large size screens.
    Density ldpi Resources for low-density (ldpi) screens (~120dpi).
    mdpi Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)
    hdpi Resources for high-density (hdpi) screens (~240dpi).
    xhdpi Resources for extra high-density (xhdpi) screens (~320dpi).
    nodpi Resources for all densities. These are density-independent resources. The system does not scale resources tagged with this qualifier, regardless of the current screen's density.
    tvdpi Resources for screens somewhere between mdpi and hdpi; approximately 213dpi. This is not considered a "primary" density group. It is mostly intended for televisions and most apps shouldn't need it—providing mdpi and hdpi resources is sufficient for most apps and the system will scale them as appropriate. If you find it necessary to provide tvdpi resources, you should size them at a factor of 1.33*mdpi. For example, a 100px x 100px image for mdpi screens should be 133px x 133px for tvdpi.
    Orientation land Resources for screens in the landscape orientation (wide aspect ratio).
    port Resources for screens in the portrait orientation (tall aspect ratio).
    Aspect ratio long Resources for screens that have a significantly taller or wider aspect ratio (when in portrait or landscape orientation, respectively) than the baseline screen configuration.
    notlong Resources for use screens that have an aspect ratio that is similar to the baseline screen configuration.

    Note: If you're developing your application for Android 3.2 and higher, see the section about Declaring Tablet Layouts for Android 3.2 for information about new configuration qualifiers that you should use when declaring layout resources for specific screen sizes (instead of using the size qualifiers in table 1).



    Designing alternative layouts and drawables

    Layout 과 Drawable 사용 유형은 전적으로 Application 의 요구사항에 따른다. 보통, 일반적으로 Layout 을 위해서는 size 와 orientation qualifier 를 사용하며, Bitmap drawables 를 위해서는 density qualifiers 를 사용한다.

    Alternative layouts

    일단 다른 screen size 의 device 에서 여러가지 테스트를 해보다보면, Application 이 추가적인 Layout 이 필요한지, 불필요한지 알아볼 수 있다.

    - 작은 스크린에서 테스트한다면, 버튼 크기가 스크린 width 와 맞지 않을 경우, 버튼 크기 및 위치를 조정해 주는 새로운 layout 이 필요하다.
    - 큰 스크린에서 테스트한다면, 너무 많은 쓸모없는 여백이 생긴다는 걸 알게 될 것이다.
    - 가로 세로 화면에 대한 테스트를 해 본다면, 세로 뷰(Portrait mode)에서 바닥에 있던 버튼이, 가로 뷰(Landscape mode)에서는 우측에 있어야 한다고 느낄 수도 있다.

    이 들을 요약해 보면, 결국 하기 사항들을 확인해 보면 된다.

    - small screen 에 적합한가?
    - 큰 screen 의 여백의 이점을 활용할 수 있도록 최적화 되었는가?
    - 가로/세로 뷰에 모두 최적화 되었는가?

    만약 내부 view 에 의해 size 가 변경되어야 하는 bitmap 을 사용한다면,(버튼의 background image) Nine-Patch bitmap files 를 사용해야 한다. Nine-Patch 파일은 stretchable 한 영역 정보가 명시되어 있는 png 파일이다. 시스템은 늘여야 한다고 판단할 경우, 이 영역만을 반복함으로써, 늘려서(stretch) display 해준다. Nine-Patch 이미지는 어떤 사이즈에도 맞출 수 있으므로, screen size 마다 별개의 file 을 만들 필요가 없다.
    하지만, screen density 에 따라서는 각각의 버젼에 대한 Nine-Patch 파일을 제공해줘야 한다.
    (Density 에 따라서 각각의 padding 영역이 조정 된 파일이 적용되어야 한다.)

    Alternative drawables

    거의 모든 application 들은 density 에 해당하는 각 drawable resource 를 가지고 있다. 기본적으로 application은 Launcher icon 을 가지고 있기 때문이다. 이들은 모든 density 에서 명확하게 표시되어야 한다.
    마찬가지로 다른 bitmap resource 를 사용하고 싶다면, 각 density 별로 폴더에 가지고 있어야 한다.

    이렇게 각 density 별로 bitmap resource 를 생성할 경우, 4개의 generalized densities 에 따라서 3:4:6:8 scaling ratio 를 따라서 생성하면 된다.

    Figure 4. Relative sizes for bitmap drawables that support each density.


    예를 들어 mdpi 용 48X48 image 파일이 있다면, 각 density 별 image size 는 아래와 같다.


    • 36x36 for low-density
    • 48x48 for medium-density
    • 72x72 for high-density
    • 96x96 for extra high-density

    Best Practices

    이 문서의 목적은 Android 가 지원하는 어떠한 screen configuration 에서도 적절히 동작하며 제대로 보이는 application 을 작성하는 것이다. 앞서 이를 위해, Application 이 각 screen configuration 에 맞게 적용시키는 방법, 그리고 어떻게 customize 하는지에 대한 방법에 대해 기술했다. 이번 section 에서는 몇 가지 Tip 과 적절한 scale 방법에 대한 technique 에 대한 overview 를 하겠다.

    다음은 서로 다른 스크린에서 application 이 적절하게 display 되는지를 보장할 수 있는 방법에 대한 Quick checklist 입니다.

    1. XML Layout file 에서 치수를 명시할 때는 wrap_content, fill_parent 또는 dp 단위를 사용해라.
    2. Application Code 내에서 pixel value 를 절대 사용하지 말라.
    3. AbsoluteLayout 을 사용하지 말라.(Deprecated)
    4. 서로 다른 screen density 에 따른 각각의 bitmap drawables 를 제공하라.

    다음은 각 항목에 대한 자세한 설명이다.

    1. XML Layout file 에서 치수를 명시할 때는 wrap_content, fill_parent 또는 dp 단위를 사용해라.

    android:layout_width 또는 android:layout_height 를 명시할 때는 wrap_content, fill_parent 또는 dp 단위를 사용하면 각 device screen size 에 맞게 적절한 size 로 변경될 것이다.
    예를 들면, layout_width="100dp" 로 명시했다면, medium density 에서는 100 pixel 로 표시되겠지만, high density screen 에서는 150 pixel 로 알아서 표시될 것이다.
    결과적으로 물리적으로는 동일한 길이로 표시된다.
    마찬가지로 text size 를 명시할 때도 sp 단위를 사용해라.

    2. Application Code 내에서 pixel value 를 절대 사용하지 말라.

    성능문제와 코드 단순화를 위해 android system 은 내부에서는 모두 pixel 단위를 표준으로 사용한다. 즉 view 의 크기는 항상 pixel 값으로 처리되며, 이는 항상 현재 screen 의 density 에 따른 계산 결과를 기반으로 한다.

    3. AbsoluteLayout 을 사용하지 말라.(Deprecated)

    대신에 RelativeLayout 을 사용해라.

    4. 서로 다른 screen density 에 따른 각각의 bitmap drawables 를 제공하라.

    비록 system 이 알아서 현 screen density 에 맞게 scale 해주겠지만, 좀 더 선명하게 보여주기 위해 density 에 따른 최적화 작업은 필요하다.

     

     

    Posted by outliers
    ,


    zxing 에서 가로모드로만 되어 있는 것을 세로 모드로 바꾸어 보겠습니다.
    zxing 버전은 2012년 11월 20일 ZxingDemo versionCode=87 입니다.
    zxing : https://github.com/zxing/zxing

    많은 블로그에서 가져와서 테스트 해본 결과 입니다.

    1. AndroidManifest.xml 에서 android:screenOrientation="portrait" 로 설정
    2. CameraConfigurationManager.java
    3.  
      	void initFromCameraParameters(Camera camera) {
      		Camera.Parameters parameters = camera.getParameters();
      		WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
      		Display display = manager.getDefaultDisplay();
      		int width = display.getWidth();
      		int height = display.getHeight();
      		// We're landscape-only, and have apparently seen issues with display thinking it's portrait 
      		// when waking from sleep. If it's not landscape, assume it's mistaken and reverse them:
      		// 아래 if 문을 주석 처리를 합니다.
      //		if (width < height) {
      //			Log.i(TAG, "Display reports portrait orientation; assuming this is incorrect");
      //			int temp = width;
      //			width = height;
      //			height = temp;
      //		}
      		screenResolution = new Point(width, height);
      		Log.i(TAG, "Screen resolution: " + screenResolution);
      		cameraResolution = findBestPreviewSizeValue(parameters, screenResolution);
      		Log.i(TAG, "Camera resolution: " + cameraResolution);
      	}
      
    4. void setDesiredCameraParameters(Camera camera, boolean safeMode) 함수에서 제일 아래 부분의 
      camera.setParameters(parameters); 전에 camera.setDisplayOrientation(90); 를 추가 합니다.
    5. CameraManager.java 파일에서 getFramingRectInPreview() 에 아래와 같은 코드를 추가 합니다.
    6.  
            rect.left = rect.left * cameraResolution.y / screenResolution.x;
            rect.right = rect.right * cameraResolution.y / screenResolution.x;
            rect.top = rect.top * cameraResolution.x / screenResolution.y;
            rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
      

       

    7. DecodeHandler.java 파일에서 private void decode(byte[] data, int width, int height) 함수에 아래와 같은 코드를 추가 합니다.
     
        byte[] portraitData = new byte[data.length];
        for (int y = 0; y < height; y++) {
        	for (int x = 0; x < width; x++) {
        		portraitData[x * height + height - y - 1] = data[x + y * width];
        	}
    	}
    	int tmp = width;
    	width = height;
    	height = tmp;
      	// 회전한 데이터를 buildLuminanceSource 에서 사용 해야 함
      	PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(portraitData, width, height);
    
      간단한 QR Code 생성은 다음에 작성하도록 하겠습니다.
      Posted by outliers
      ,

      Activity 에서 onKeyDown()를 아래와 같이 Override 하면 된다.

       

      	@Override
      	public boolean onKeyDown(int keyCode, KeyEvent event) {
      		switch (keyCode) {
      		case KeyEvent.KEYCODE_BACK:
      			return true;
      		}
      		return super.onKeyDown(keyCode, event);
      	}
      
      Posted by outliers
      ,

      Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

      10. toString 메소드는 항상 오버라이드 하자.

      • 모든 서브 클래스들은 이 메소드를 오버라이드 할 것을 권한다. toString 메소드를 잘 구현하면 우리 클래스를 더욱 편하게 사용할 수 있다.
      • 클래스에서 toString 메소드를 잘 구현하면, 자신의 인스턴스는 물론이고 그 인스턴스들의 참조를 갖고 있는 객체들도 toString 메소드의 장점을 가질 수 있다. 가능하다면 toString 메소드에서는 객체의 모든 중요한 정보를 반환해야 한다. 하지만 객체가 너무 크거나 하면 요약된 정보만을 반환해야 할 것이다.
      • toString 메소드 반환 값의 형식을 규정 시 단점이 있다. 그 클래스가 여러 곳에서 사용될 경우, 한번 정해 놓으면 두고두고 신경 써야 한다는 것이다.
      • 표현 형식의 규정 여부와는 무관하게 아무튼 그 의도를 명쾌하게 문서화해야 한다.
      • 형식의 규정 여부와는 관계 없이, toString 메소드의 반환 값에 포함되는 모든 정보를 프로그램적으로 접근하는 방법을 제공하자.

       

       

       	/**
      	 * PhoneNumber 객체(전화번호)의 문자열 표현을 반환한다.
      	 * 문자열은 14자이며 형식은 "(XXX) YYY-ZZZZ" 이다.
      	 * 여기서 XXX는 지역번호이고, YYY는 국번호, ZZZZ은 선번호이다.
      	 * 각 영문 대문자는 한 자리의 십진수를 나타낸다.
      	 * 지정된 자리수가 다 채워지지 않은 경우는 세 부분 모드 0을 앞에 붙인다.
      	 * 예를 들어, 선번호의 값이 123이면, 문자열 표현 시 "0123"이 된다.
      	 * 지역번호의 우 괄호 다음에는 스페이스를 하나 추가한다.
      	 */
      	@Override
      	public String toString() {
      		return String.format("(%03d) %03d-%04d", 
      							areaCode, prefix, lineNumber);
      	}
      	
      	// 만일 이 클래스의 객체를 문자열로 표현하는 형식을 규정하지 않는다면, 다음과
      	// 같이 주석을 넣는게 좋을 것이다.
      	
      	/**
      	 * 이 부분의 간략한 표현을 반환한다.
      	 * 반환 문자열의 형식은 정해지지 않았으므로 변결될 수 있다.
      	 * 일반적인 형태는 다음과 같다:
      	 * 
      	 * "[Potion #9: type=love, smell=turpentine, look=india link]"
      	 */
      	@Override
      	public String toString() { ... }	
      
      Posted by outliers
      ,

      Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

      9. equals메소드를 오버라이드 할 때는 hashCode 메소드도 항상 같이 오버라이드 하자.

      Object.hashcode 메소드 명세서에서 가져 온 계약 사항은 다음과 같다.

      • 애플리케이션 실행 중에 같은 객체에 대해 한 번 이상 호출되더라도 hashCode 메소드는 같은 정수를 일관성 있게 반환해야 한다(equals 메소드에서 비교하는 객체의 값이 변경되지 않는다면).
        단, 이 정수 값은 애플리케이션이 매번 다시 실행될 때마다 일관되게 같을 필요는 없다.
      • equals(Object) 메소드 호출 결과 두 객체가 동일하다면, 두 객체 각각에 대해 hashCode 메소드를 호출했을 때 같은 정수 값이 나와야 한다.
      • equals(Object) 메소드 호출 결과 두 객체가 다르다고 해서 두 객체 각각에 대해 hashCode메소드를 호출했을 때 반드시 다른 정수 값이 나올 필요는 없다. 그러나 같지 않은 객체들에 대해 hashCode 메소드에서 서로 다른 정수 값을 반환하면, 이 메소드를 사용하는 해시 컬렉션들(HashMap, HashSet, Hashtable등)의 성능을 향상시킬 수 있음을 알아야 한다.

      hashCode의 오버라이딩에 실패했을 때 위배되는 주요 조항은 두 번째 것으로써, 동일한 객체들은 같은 해시 코드 값을 가져야 한다는 것이다.

       
      	// 최악의 hashCode 메소드 - 절대 이렇게 사용하지 말 것!
      	@Override
      	public int hashCode() {
      		return 42;
      	}
      

       

      HashCode 를 만드는 간단한 방법

      1. 예를 들어, 17과 같이  0이 아닌 어떤 상수 값을 result라는 int 변수에 저장한다.
      2. 우리 객체의 각 주요 필드(equals 메소드에서 비교하는) f에 대해 다음을 수행한다.
        1. 각 필드에 대한 int 타입의 해시 코드 c를 다음과 같이 산출한다.
          1. 필드 f가 boolean 타입이면, (f ? 1 : 0)
          2. 필드 f가 byte, char, short, int 타입이면 (int)f
          3. 필드 f가 long 타입이면, (int)(f ^ (f >>> 32)).
          4. 필드 f가 float 타입이면 Float.floatToIntBits(f)
          5. 필드 f가 double 타입이면 Double.doubleToLongBits(f)를 실행한 후 반환된 long 타입의 값을 앞의  III 처럼 처리하여 해시 코드 값을 구한다.
          6. 필드 f가 객체 참조일 경우는, 현재(equals 메소드가 호출된) 객체의 equals 메소드에서 그 필드를 비교하기 위해 f가 참조하는 객체의 equals 메소드를 재귀적으로 호출한다. 그러면 그 객체의 필드에 대해 hashCode 메소드도 재귀적으로 자동 호출된다. 만일 더 복잡한 비교(객체의 여러 필드를 비교하거나, 필드의 복잡한 연산과 같은)가 필요하다면, 필드의 "표준 형식"을 만들어 처리하고 그 표준 형식에 대해 hashCode 메소드를 호출한다. 만일 필드 f의 값이 null이면, 0을 반환한다(또는 다른 어떤 상수 값도 가능하지만 관례적으로 0을 사용한다.)
          7. 필드 f가 배열이라면 배열의 각 요소를 별개의 필드처럼 처리한다. 즉, 위의 규칙들을 적용하여 처리를 해야 할 요소 각각의 해시 코드 값을 산출한다. 그리고 바로 밑의 2.2 수식을 적용하여 그값들의 합을 구한다. 만일 배열 필드의 모든 요소를 처리해야 한다면 자바 1.5 버전에 새로 추가되어 오버로딩 된 Arrays.hashCode 메소드들 중 하나를 사용할 수 있다.
        2. 앞의 2.1 단계에서 구한 코드 c를 result에 합계한다.
          result = 31 * result + c;
        3. result 를 반환한다.
        4. hashCode 메소드 작성이 끝나면 동일한 인스턴스들이 같은 값의 해시 코드를 갖는지 검토하자. 그리고 단위 테스트를 작성하여 잘 실행되는지 검증하자.

       

       
      	// 어떤 클래스의 세 개의 중요 필드가 있고, 모두 short 타입 일 경우
      	@Override
      	public int hashCode() {
      		int result = 17;
      		result = 31 * result + areaCode;
      		result = 31 * result + prefix;
      		result = 31 * result + lineNumber;
      		return result;
      	}
      
      Posted by outliers
      ,

      Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

      8. equals 메소드를 오버라이딩 할 때는 보편적 계약을 따르자.

      다음 조건 중 어느 하나라도 만족하면 equals 오버라이드를 하지 않고 상속 받은 그대로 사용하자.

      • 클래스의 각 인스턴스가 본래부터 유일한 경우.
      • 두 인스턴스가 논리적으로 같은지 검사하지 않아도 되는 클래스의 경우
      • 수퍼 클래스에서 equals 메소드를 이미 오버라이딩 했고, 그 메소드를 그대로 사용해도 좋은 경우
      • private이나 패키지 전용(package-private) 클래스라서 이 클래스의 equals 메소드가 절대 호출되지 않아야 할 경우

       

      객체 참조만으로 인스턴스의 동일 여부를 판단하는 것이 아니라, 인스턴스가 갖는 값을 비교하여 논리적으로 같은지 판단할 필요가 있는 클래스로써, 자신의 수퍼클래스에서 equals 메소드를 오버라이드 하지 않았을 때 Object.equals 를 오버라이드 하는 것이 좋다.

      equals 메소드를 오버라이드 할 때는 이 메소드의 보편적 계약을 따라야 한다.
      equals 메소드는 동등 관계(equivalence relation)을 구현하며, 그것은

      • 재귀적이다(Reflexive) : null이 아닌 모든 참조 값 x에 대해, x.equals(x)는 반드시 true를 반환해야 한다.
      • 대칭적이다(Symmetric) : null이 아닌 모든 참조 값 x와 y에 대해, y.equals(x)가 true를 반환한다면 x.equals(y)도 반드시 true를 반환해야 한다.
      • 이행적이다(Transitive) : null이 아닌 모든 참조 값 x, y, z에 대해, 만일 x.equals(y)가 true를 반환하고 y.equals(z)가 true를 반환한다면 x.equals(z)도 반드시 true를 반환해야 한다.
      • 일괄적이다(Consistent) : null이 아닌 모든 참조 값 x와 y에 대해, equals 메소드에서 객체 비교 시 사용하는 정보가 변경되지 않는다면, x.equals(y)를 여러 번 호출하더라도 일관성 있게 true 또는 false를 반환해야 한다.
      • null이 아닌 모든 참조 값 x에 대해, x.equals(null)은 반드시 false를 반환해야 한다.

       

      좋은 equals 메소드를 만드는 방법은 다음과 같다.

      1. 객체의 값을 비교할 필요 없고 참조만으로 같은 객체인지 비교 가능하다면 == 연산자를 사용하자.
      2. instanceof 연산자를 사용해서 전달된 인자가 올바른 타입인지 확인하자.
      3. 인자 타입을 올바른 타입으로 변환한다.
      4. 클래스의 중요한(꼭 비교해야 하는) 필드 각각에 대해서는 인자로 전달된 객체의 필드와 현재 객체(equals) 메소드가 호출된)의 필드가 모두 같은지 빠뜨리지 말고 비교한다.
      5. 우리의 equals 메소드를 작성한 후에는 보편적 계약을 따르는지 확인하고 단위 테스트 코드를 작성하여 그런 속성들이 지켜지는지 검사한다.

       

      유의 사항

      • equals 메소드를 오버라이드 할 때는 hashCode 메소드도 항상 오버라이드 한다.
      • 너무 똑똑한 척 하지마라. 단순히 필드 값이 같은지 검사하는 것이라면 equals 계약 준수가 어렵지 않다. 하지만 너무 지나치게 동일 여부를 비교하려 하면 문제가 생기기 쉽다.
      • equals 메소드의 인자 타입을 Object 대신 다른 타입으로 바꾸지 말자.

       

       

      Posted by outliers
      ,

      Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

      7. 파이널라이저(finalizer)의 사용을 피하자.

      1. 신속하게 실행된다는 보장이 없다.
        객체가 사용할 수 없게 되는 시점부터 파이널라이저가 실행되는 시점까지는 긴 시간이 소요될 수 있다. 파이널라이저 내부에서는 실행 시간이 매우 중요한 작업을 절대 하지 말아야 한다는 것이다.

      2. 파이널라이즈를 하는 동안 catch 되지 않은 예외가 발생하면 그 예외는 무시되고 그 객체의 파이널 라이즈는 종결된다.

      3. 파이널라이저를 사용하면 엄청난 성능 저하가 발생한다.

      파일이나 스레드처럼 종결 작업이 필요한 자원을 갖는 객체들의 클래스에서는 파이널라이저 대신 무었을 써야 할까?
      작업이나 자원을 정상적으로 종료하는 메소드만 별도로 추가하면 된다. 그리고 더 이상 필요 없는 각 인스턴스에 대해서 그 클래스의 클라이언트가 종료 메소드를 호출하도록 하면 된다.

       

      파이널라이저는 어떤 경우에 사용하면 좋을까??

      1. 생성된 객체를 갖고 있는 코드에서 그 객체의 종료 메소드 호출을 빠뜨렸을 경우에 "안전망"의 역할을 하는 것이다.
        즉, 클라이언트가 종료 메소드 호출에 실패하는 그런 경우(거의 없기를 바라지만)를 대비해서 파이널라이저를 사용한다.

      2. 네이티브 피어(native peer) 객체와 관련이 있다.
        네이티브 피어는 일반 자바 객체가 아니므로, 그것과 연관된 자바 피어 객체가 소멸되면 가비지 컬렉터가 알지 못하며 재활용 할 수도 없다. 따라서 이런 경우 파이널라이저가 적합한 수단이 된다.

      "파이널라이저의 연쇄 호출(chaining)" 은 자동으로 실행되지 않는다는 것에 유의하자.

       

      요약

      • 종료 메소드 호출을 빼먹은 경우를 대비한 안전망의 역할이나, 또는 중요하지 않은 네이티브 자원을 종결하는 경우 외에는 파이널라이저를 사용하지 말자.
      • 어쩔 수 없이 파이널라이저를 사용해야 하는 그런 경우에는 super.finalize()를 호출하는 것을 잊지 말자.
      • 만일 안전망의 역할로 파이널라이저를 사용한다면, 부적절한 상황(자원 사요잉 끝나지 않은 객체를 파이널라이즈하는)을 메시지로 기록해야 한다는 것을 잊지 말자.
      • public 이고 final이 아닌 클래스에 파이널라이저가 필요하다면, 파이널라이저 가디언의 사용을 고려하자. 서브 클래스의 파이널라이저에서 super.finalize 호출에 실패하더라도 파이널라이즈가 될 수 있기 때문이다.
      Posted by outliers
      ,

      Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

      6. 쓸모없는 객체 참조를 제거하자.

      1. 어떤 클래스에서 자신의 메모리를 자가기 관리 한다면, 프로그래머는 항상 메모리 누출에 주의 해야 한다.
        따라서 특정 배열 요소가 자유로 사용 가능해질 때는 그 요소에 저장되었떤 객체 참조를 반드시 null 값으로 변경해야 한다.

         
        // 어디에서 "메모리 누출"이 생기는지 찾을 수 있는가?
        public class Stack {
        	private Object[] elements;
        	private int size = 0;
        	private static final int DEFAULT_INITIAL_CAPACITY = 16;
        	
        	public Stack() {
        		elements = new Object[DEFAULT_INITIAL_CAPACITY];
        	}
        	
        	public void push(Object e) {
        		ensureCapacity();
        		elements[size++] = e;
        	}
        	
        	public Object pop() {
        		if (size == 0)
        			throw new EmptyStackException();
        		return elements[--size];
        	}
        	
        	/**
        	 * 배열 요소를 저장하는 필요한 공간을 확인하고
        	 * 배열이 커질 필요가 있을 때는 그 크기를 2배로 늘린다.
        	 */
        	private void ensureCapacity() {
        		if (elements.length == size)
        			elements = Arrays.copyOf(elements, 2 * size + 1);
        	}
        }


        객체들을 가리키는 쓸모 없는 참조를 스택에서 여전히 가지고 있다. 해결책은 쓸모 없는 참조를 null로 만드는 것이다.

         
        public Object pop() {
        	if (size == 0)
        		throw new EmptyStackException();
        	Object result = elements[--size];
        	elements[size] = null; // 쓸모 없는 참조를 제거한다.
        	return result;
        }
        


        이런 문제로 고통을 껵어 본 프로그래머들은 코드 실행이 끝나는 즉시로 너무 지나치게 모든 객체 참조를 null 값으로 바꾸려 한다. 그것은 바람직하지 않다. 프로그램 코드가 필요 이상으로 어수선해지기 때문이다. 객체 참조를 null로 변경하는 것은 꼭 필요할 때만 예외적으로 행해야 한다. 쓸모 없는 참조를 제거하는 가장 좋은 방법은, 참조 값을 갖는 변수가 유효 범위(scope) 밖에 있도록 하는 것이다. 만일 그런 변수가 최소한의 유효 범위 내에 있도록 정의 한다면 자연스레 그렇게 될 것이다.

      2. 메모리 누출이 흔히 생기는 또 다른 근원은 캐시(cache)이다.

        캐시 외부에 캐시의 키(key)에 대한 참조가 있을 동안만 캐시에 저장된 항목이 유효한 그런 캐시를 구현하는 것으로 충분하다면, WeakHashMap을 캐시로 사용하자. 그러면 키로 저장된 객체가 더 이상 참조되지 않을 때 해당 항목이 자동으로 삭제될 것이다. 캐시에 저장된 항목들의 생명주기가 각 항목의 키(값이 아닌)에 대한 외부 참조에 의해 결정되도록 할 때에만 WeakHashMap이 유용하다는 것을 기억하자.

      3. 메모리 누출의 세 번째 근원은 리스너(Listener)와 콜백(callback)이다.
        클라이언트가 콜백을 등록하되 말소는 하지 않는 API를 구현한다면 우리가 뭔가 조치를 취하지 않는 한 콜백은 계속 누적될 것이다.

        콜백이 신속하게 가비지 컬렉션 되도록 하는 가장 좋은 방법은 약한 참조(weak reference)만을 저장 유지하는 것이다. 예를 들어 WeakHashMap의 키로만 콜백을 저장한다.
      Posted by outliers
      ,