Android Support Annotations 라이브러리를 활용한 결함 탐지방법

1. Annotations 이란 ?

 - Annotation 은 Java 코드에서 추가할 수 있는 메타데이터로, @ 기호로 시작한다.

 - 상위 클래스의 메서드를 오버라이드 한다는 정보를 표현하는 @Override 애너테이션이 대표적이다.

 - 추가 정보를 문법적으로 표현할 수 있기 때문에 Java 에서는 API의 의도를 애너테이션으로 명시하고 결함 탐지에 활용하는 기법이 발달 했다.

 

2. Java 에서 제공되는 Annotations

 - @Override : 함수 Override 일 경우에 사용되는 Annotations

 - @Deprecated : 해당 변수, 함수 명이 삭제될 수 있음을 나타낼 때 사용

 - @SuppressWarnings : 권장하지 않는 구문에 대하여 노랑색으로 경고를 표시해 주는 경우

 

3. Android Support Library 의 Annotations

build.gradle 에 아래의 코드를 추가하면 사용 가능하다.

dependencies {

   compile 'com.android.support:support-annotations:20.0.0'

}

 

3.1 @StringRes, @DrawableRes, @ColorRes

위 세가지의 Annotations 는 리소스 아이디 관련 애너테이션이다. 요소의 값이 이 애너테이션들이 의미하는 리소스 타입에 해당하는 리소스 아이디임을 의미한다.

Android 의 모든 리소스는 R 클래스에 의해 int 타입의 아이디로 관리된다. 그래서 drawable 타입 리소스의 아이디를 넣어야 할 곳에 문자열 리소스의 아이디나 정수 값을 넣는 등 실수를 범할 수 있는데, 이 애너테이션을 이용하면 실수를 방지할 수 있다.

void setMessage(@StringRes int resId) {  
    mMessage = mContext.getText(resId);
}

// ...

setMessage(R.string.error_retry);    // OK

int stringId = R.string.error_retry;  
setMessage(stringId);                // OK

setMessage(R.color.white);           // ERROR: Expected resource of type string  
setMessage(1);                       // ERROR: Expected resource of type string 

 

3.2 @ColorInt

@ColorInt 이너테이션은 해당 값이 0xff99ff99와 같은 ARGB 컬러 정수임을 나타낸다. 글자가 비슷한 @ColorRes 애너테이션은 R.color.divider 와 같은 Color Drawable 타입 리소스의 아이디를 나타내므로 혼동하지 않도록 주의한다.

다음 코드는 int 타입 파라미터의 값을 @ColorInt 애너테이션과 @ColorRes 애너테이션으로 명확하게 구분한 예이다.

void setColor(@ColorInt int color) {  
    mColor = color;
}

void setColorRes(@ColorRes int resId) {  
    setColor(mContext.getResources().getColor(resId));
}

// ...

setColor(0xff99ff99);         // OK  
setColor(R.color.divider);    // ERROR: Should pass resolved color instead of resource id  
                              //        here: `getResources().getColor(R.color.divider)`

setColorRes(0xff99ff99);      // ERROR: Expected resource of type color  
setColorRes(R.color.divider); // OK  

 

3.3 @IntRange, @FloatRange

@IntRange 애너테이션 @FloatRange 애너테이션은 숫자형 값의 범위를 한정한다. from 파라미터와 to 파라미터를 지니며, 값의 범위는 from 파라미터의 값부터 to 파라미터의 값 사이다. 투명도에서 0~1 범위의 소숫값(decimal)을 사용하는지, 색상 표현에서 0~255 범위의 정숫값을 사용하는지 혼동하기 쉬운데, 이런 경우에 유용하게 쓰일 수 있다. @IntRange 애너테이션은 int 타입뿐만 아니라 long 타입에도 사용할 수 있다. 마찬가지로 @FloatRange 애너테이션은 float 타입뿐만 아니라 double 타입에도 사용할 수 있다.

다음 코드는 @FloatRange 애너테이션으로 alpha 파라미터의 값이 0.0~1.0이어야 함을 나타내는 예다.

void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {  
    // if (alpha < 0 || alpha > 1.0f) {
    // throw new IllegalArgumentException();
    // }
}

// ...

setAlpha(0.5f); // OK  
setAlpha(127);  // ERROR: Value must be ≥ 0.0 and ≤ 1.0 (was 127)  

 

3.4 @UiThread, @WorkerThrea

@UiThread 애너테이션 @WorkerThread 애너테이션, 은 스레드 관련 애너테이션이다. 이 애너테이션들이 의미하는 스레드와 동일한 유형의 스레드에서만 해당 메서드를 호출할 수 있도록 제약한다.

@WorkerThread
void backgroundJob() {  
}

@UiThread
void uiJob() {  
}

// ...

@WorkerThread
void backgroundJob2() {  
    backgroundJob();                  // OK
    uiJob();                          // ERROR: Method uiJob must be called from the UI
                                      // thread, currently inferred thread is worker
    view.setVisibility(View.VISIBLE); // ERROR: Method setVisibility must be called from
                                      // the UI thread, currently inferred thread is
                                      // worker
}

@UiThread
void uiJob2() {  
    backgroundJob();                  // ERROR: Method backgroundJob must be called from
                                      // the worker thread, currently inferred thread is
                                      // UI
    uiJob();                          // OK
    view.setVisibility(View.VISIBLE); // OK
}

 

3.5 @CallSuper

@CallSuper 애너테이션은 이 애너테이션이 붙은 메서드를 하위 클래스에서 오버라이드할 때는 반드시 상위 클래스의 메서드를 호출하도록 강제한다. 액티비티의 라이프사이클 메서드에도 사용된다.

다음 코드는 foo() 메서드에 @CallSuper 애너테이션을 붙여 foo() 메서드를 오버라이드한 하위 클래스에서 반드시 super.foo() 메서드를 호출하도록 강제하는 예다.

 

class Super {  
    @CallSuper
    void foo() {
    }

    void bar() {
    }
}

// ...

class Example1 extends Super {  
    @Override
    void foo() {                // ERROR: Overriding method should call 'super.foo'
    }

    @Override
    void bar() {                // OK
    }
}

class Example2 extends Super {  
    @Override
    void foo() {                // OK
        super.foo();
    }

    @Override
    void bar() {                // OK
        super.bar();
    }
}

class ExampleActivity extends Activity {  
    protected void onCreate(Bundle saved) { // ERROR: Overriding method should call
                                            //        'super.onCreate'
    }
}

 

3.6 @NonNull, @Nullable

 

@NonNull 애너테이션 @Nullable 애너테이션은 null 값 처리에 관련된 애너테이션이다.

@NonNull 애너테이션은 값이 'null'이 아니라는 것을 나타낸다. 예를 들어 @NonNull 애너테이션이 붙은 변수에 null 값을 대입하면 경고가 나타난다.

@Nullable 애너테이션은 값이 'null'일 수 있다는 것을 나타낸다. 예를 들어 @Nullable 애너테이션이 붙은 변수를 null 검사 없이 사용하면 경고가 나타난다.

다음 코드는 필드, 파라미터, 메서드에 @NonNull 애너테이션과 @Nullable 애너테이션을 사용한 예다.

 

class Example {  
    @NonNull
    final Context mContext;
    @Nullable
    View mView;

    Example(@NonNull Context context) {
        // context 파라미터에 @NonNull 애너테이션이 붙어 있으므로
        // 파라미터의 값이 null이 아닐 것이라 가정한다.
        // 그래서 null 검사가 필요 없다.
        // if (context == null) {
        // throw new NullPointerException("context");
        // }
        mContext = context;
    }

    @NonNull
    Context getContext() {
        return mContext;
    }

    void setView(@Nullable View view) {
        mView = view;
    }

    @Nullable
    View getView() {
        return mView;
    }
}

// ...

Context context = null;  
new Example(context);        // WARNING: Argument 'context' might be null

new Example(null);           // WARNING: Passing 'null' argument to parameter annotated as @NonNull

new Example(nonNullContext); // OK

View view = getView();  
view.getTag();               // WARNING: Method invocation 'view.getTag()' may produce  
                             // 'java.lang.NullPointerException'

@NonNull View mView;
mView = getView();           // WARNING: Expression 'getView()' might evaluate to null but  
                             // is assigned to a variable that is annotated with @NonNull

 

http://d2.naver.com/helloworld/8725603

http://thdev.net/616

'Android' 카테고리의 다른 글

[AndroidStudio] git clone 방법  (0) 2023.05.27

+ Recent posts