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
'Android' 카테고리의 다른 글
[AndroidStudio] git clone 방법 (0) | 2023.05.27 |
---|