Android 주석 프레임 워 크 비교 분석

14692 단어 Android주해프레임
자바 의 주석(Annotation)은 하나의 태그 에 해당 합 니 다.프로그램 에 주 해 를 넣 으 면 프로그램 에 특정한 표 시 를 하 는 것 과 같 습 니 다.표 시 는 가방,클래스,속성,방법,로 컬 변수 에 추가 할 수 있 습 니 다.그 다음 에 주해 처리 기 를 써 서 이 주해(인칭 컴 파일 시 주해)를 처리 할 수도 있 고 프로그램 이 실 행 될 때 반 사 를 이용 하여 주 해 를 받 아 해당 하 는 처 리 를 할 수도 있다.
안 드 로 이 드 프로그램 을 개발 할 때 끝 없 는 findViewById,setOnClickListener 등 방법 은 대부분의 개발 자 들 을 골 치 아 프 게 했다.다행히 시장 에서 이른바 주해 프레임 워 크 는 개발 자 들 이 과정 을 간소화 하 는 데 도움 을 줄 수 있다.비교적 유행 하 는 것 은 butterknife,annotations,xutils,afinal,roboguice 등 이 있다.오늘 우 리 는 이 주해 틀 들 을 비교 해 보 자.
ButterKnife 프레임 분석
       먼저 Butterknife 를 살 펴 보 자.Jakewharton 대신 들 의 역작 으로 접속 이 간단 하고 라 이브 러 리 에 의존 하 는 것 이 특징 이다.또한 Android Studio 에 서 는 주석 과 클래스 속성 을 자동 으로 생 성 하 는 플러그 인 을 제공 합 니 다.
       Butterknife 가 현재 지원 하 는 주 해 는 View 바 인 딩(Bind),자원 바 인 딩(BindBool,BindColor,BindDimen,BindDrawble,BindInt,BindString),이벤트 바 인 딩(OnCheckedChanged,OnClick,OnEditor Action,OnFocusChange,OnItemClick,OnItemLongClick,OnItemSelected,OnLongClick,OnPageChange,OnTextChanged,OnTouch)입 니 다.
       Butterknife 의 원 리 는 운행 시 주석 이다.다음 데모 부터 보 겠 습 니 다.

public class MainActivity extends Activity {

 @Bind(R.id.tv1)
 TextView mTv1;
 @Bind(R.id.tv2)
 TextView mTv2;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  ButterKnife.bind(this);
  mTv1.setText("tv1          ");
 }

 @OnClick(R.id.tv2)
 public void tv2OnClick() {
  Toast.makeText(this, "tv2    ", Toast.LENGTH_SHORT).show();
 }
이것 은 View 바 인 딩 의 예 입 니 다.구성원 변수 에 바 인 딩 이 필요 한 컨트롤 id 를 주석 한 다음 ButterKnife.bid(Activity target)방법 으로 주석 이 있 는 구성원 변 수 를 할당 해 야 합 니 다.ok,ButterKnife.bind()가 어떻게 일 하 는 지 보 세 요.

/**
 * Bind annotated fields and methods in the specified {@link Activity}. The current content
 * view is used as the view root.
 *
 * @param target Target activity for view binding.
 */
 public static void bind(Activity target) {
 bind(target, target, Finder.ACTIVITY);
 }
위의 코드 에서 알 수 있 듯 이 최종 적 으로 bind(Object target,Object source,Finder finder)방법 을 호출 해 야 합 니 다.

static void bind(Object target, Object source, Finder finder) {
 Class<?> targetClass = target.getClass();
 try {
  if (debug) Log.d(TAG, "Looking up view binder for " + targetClass.getName());
  ViewBinder<Object> viewBinder = findViewBinderForClass(targetClass);
  if (viewBinder != null) {
  viewBinder.bind(finder, target, source);
  }
 } catch (Exception e) {
  throw new RuntimeException("Unable to bind views for " + targetClass.getName(), e);
 }
 }
이 방법 은 해당 하 는 ViewBinder 대상 을 찾 거나 생 성 한 다음 해당 대상 의 bid(Finder finder,T target,Object source)방법 을 주 해 된 변수 에 할당 하 는 것 입 니 다.findViewBinderForClass(Classcls)방법.

private static ViewBinder<Object> findViewBinderForClass(Class<?> cls)
  throws IllegalAccessException, InstantiationException {
 ViewBinder<Object> viewBinder = BINDERS.get(cls);
 if (viewBinder != null) {
  if (debug) Log.d(TAG, "HIT: Cached in view binder map.");
  return viewBinder;
 }
 String clsName = cls.getName();
 if (clsName.startsWith(ANDROID_PREFIX) || clsName.startsWith(JAVA_PREFIX)) {
  if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
  return NOP_VIEW_BINDER;
 }
 try {
  Class<?> viewBindingClass = Class.forName(clsName + ButterKnifeProcessor.SUFFIX);
  //noinspection unchecked
  viewBinder = (ViewBinder<Object>) viewBindingClass.newInstance();
  if (debug) Log.d(TAG, "HIT: Loaded view binder class.");
 } catch (ClassNotFoundException e) {
  if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());
  viewBinder = findViewBinderForClass(cls.getSuperclass());
 }
 BINDERS.put(cls, viewBinder);
 return viewBinder;
 }
       반 사 를 이용 하여 하나의 ViewBinder 대상 을 만 들 고 캐 시 도 있 음 을 알 수 있 습 니 다.즉,같은 class 가 여러 번 호출 되면 한 번 만 반 사 됩 니 다.반 사 는 원생 코드 보다 느 리 지만 한 번 만 반사 된다 면 성능 에 미 치 는 영향 은 무시 할 수 있다.문 제 는 이 반사 로 생 성 된 ViewBinder 가 무엇 인지 입 니 다.bind(Finder finder,T target,Object source)방법 은 주 해 된 변수 에 어떻게 값 을 부여 합 니까?
       위 에서 말 했 듯 이 Butterknife 프레임 워 크 는 컴 파일 할 때 주해 입 니 다.보통 이런 주 해 는 컴 파일 할 때 주해 표지 에 따라 동적 으로 일부 종 류 를 생 성하 거나 xml 를 생 성하 면 됩 니 다.운영 시기 에 이런 주 해 는 없습니다~동적 으로 생 성 된 종 류 를 통 해 조작 을 합 니 다.반사 가 없 기 때문에 효율 과 직접 호출 방법 은 별 차이 가 없습니다~~프로그램 을 컴 파일 할 때 Butterknife 는 모든 주석 에 따라 해당 하 는 코드 를 생 성 합 니 다.예 를 들 어 위의 MainActivity 류,Butterknife 는 생 성 됩 니 다.

public class MainActivity$ViewBinder<T extends MainActivity> implements ButterKnife.ViewBinder<T> {
 
 public void bind(ButterKnife.Finder finder, final T target, Object source) {
 target.mTv1 = ((TextView)finder.castView((View)finder.findRequiredView(source, 2131492971, "field 'mTv1'"), 2131492971, "field 'mTv1'"));
 View localView = (View)finder.findRequiredView(source, 2131492972, "field 'mTv2' and method 'tv2OnClick'");
 target.mTv2 = ((TextView)finder.castView(localView, 2131492972, "field 'mTv2'"));
 localView.setOnClickListener(new DebouncingOnClickListener() {
  public void doClick(View paramAnonymousView) {
  target.tv2OnClick();
  }
 });
 }

 public void unbind(T target) {
 target.mTv1 = null;
 target.mTv2 = null;
 }
}

이 를 통 해 알 수 있 듯 이 Bind 주 해 는 마지막 에 생 성 된 코드 를 호출 하여 findViewById 에 값 을 부여 하 는 것 입 니 다.이 벤트 는 view 에 기본 적 인 이 벤트 를 설정 한 다음 에 주 해 를 호출 하 는 방법 입 니 다.따라서 성능 상 ButterKnife 는 app 에 영향 을 주지 않 습 니 다.Butterknife 가 자동 으로 생산 하 는 코드 도 많 지 않 아 프로그램의 가방 크기 에 영향 을 주지 않 습 니 다.
Android Annotations 프레임 워 크 분석
      유명한 Annotations 프레임 워 크 를 분석 해 보 자.이 프레임 워 크 의 원 리 는 Butterknife 와 마찬가지 로 컴 파일 할 때 코드 를 생 성 합 니 다.그러나 annotations 는 코드 를 생 성하 여 주 해 를 가 진 변수,방법 에 값 을 부여 하 는 것 이 아니 라 계승 대 주 해 를 가 진 종 류 를 직접 생 성 합 니 다.이 종 류 는 변수 에 값 을 부여 하고 주해 방법 에 호출 하 는 코드 가 있 습 니 다.실행 할 때,우리 가 쓴 클래스 가 아 닌 annotations 에서 생 성 된 클래스 를 직접 실행 합 니 다.이렇게 많아우리 가 쓴 종 류 를 먼저 보 자.

@EActivity(R.layout.content_main)
public class MainActivity extends Activity {

 @ViewById(R.id.myInput)
 EditText myInput;

 @ViewById(R.id.myTextView)
 TextView textView;

 @Click
 void myButton() {
  String name = myInput.getText().toString();
  textView.setText("Hello "+name);
 }
}
annotations 에서 생 성 된 클래스 를 다시 보 세 요.

public final class MainActivity_
 extends MainActivity
 implements HasViews, OnViewChangedListener
{

 private final OnViewChangedNotifier onViewChangedNotifier_ = new OnViewChangedNotifier();

 @Override
 public void onCreate(Bundle savedInstanceState) {
  OnViewChangedNotifier previousNotifier = OnViewChangedNotifier.replaceNotifier(onViewChangedNotifier_);
  init_(savedInstanceState);
  super.onCreate(savedInstanceState);
  OnViewChangedNotifier.replaceNotifier(previousNotifier);
  setContentView(layout.content_main);
 }

 private void init_(Bundle savedInstanceState) {
  OnViewChangedNotifier.registerOnViewChangedListener(this);
 }

 @Override
 public void setContentView(int layoutResID) {
  super.setContentView(layoutResID);
  onViewChangedNotifier_.notifyViewChanged(this);
 }

 @Override
 public void setContentView(View view, LayoutParams params) {
  super.setContentView(view, params);
  onViewChangedNotifier_.notifyViewChanged(this);
 }

 @Override
 public void setContentView(View view) {
  super.setContentView(view);
  onViewChangedNotifier_.notifyViewChanged(this);
 }

 public static MainActivity_.IntentBuilder_ intent(Context context) {
  return new MainActivity_.IntentBuilder_(context);
 }

 public static MainActivity_.IntentBuilder_ intent(Fragment supportFragment) {
  return new MainActivity_.IntentBuilder_(supportFragment);
 }

 @Override
 public void onViewChanged(HasViews hasViews) {
  myInput = ((EditText) hasViews.findViewById(id.myInput));
  textView = ((TextView) hasViews.findViewById(id.myTextView));
  {
   View view = hasViews.findViewById(id.myButton);
   if (view!= null) {
    view.setOnClickListener(new OnClickListener() {


     @Override
     public void onClick(View view) {
      MainActivity_.this.myButton();
     }

    }
    );
   }
  }
 }
}

방법 호출 체인:onCreate(Bundle saveInstanceState)--->setContentView()--->onView Changed Notifier.notifyViewChanged(),onViewChanagedNotifier.notifyViewChanged()방법 은 최종 적 으로 onViewChanged(HasViews hasViews)방법 을 호출 합 니 다.이 방법 에는 변수 할당,이벤트 방법 설정 코드 가 있 습 니 다.자동 으로 생 성 된 클래스 의 이름 을 주의 깊 게 보 세 요.규칙 을 발 견 했 습 니 다.바로 우리 가 쓴 클래스 의 이름 뒤에''을 추가 하 는 것 입 니 다.기호,Annotations 프레임 워 크 를 사용 하 는 이 유 를 알 고 있 습 니 다.우리 AndroidManifest.xml 에 Activity 설정,Activity 이름 에''을 하나 더 추가 해 야 합 니 다.기호 지?진짜 로 불 러 온 것 은 AndroidAnnotations 에서 생 성 된 코드 이기 때문이다.여기까지 썼 습 니 다.annotations 프레임 워 크 에 반사 가 하나 도 없습니다.맞아요.이 프레임 워 크 는 반 사 를 사용 하지 않 았 고 초기 화 되 지 않 았 습 니 다.모든 작업 이 컴 파일 할 때 했 기 때문에 우리 프로그램 에 어떠한 속도 에 도 영향 을 주지 않 습 니 다.
       그럼 Annotations 는 어떤 주 해 를 지원 합 니까?Annotations 의 성능 이 Butterknife 와 크게 다 르 지 않 은 이상 기능 은?여기 서 홈 페이지 의 Features 를 번역 해 보 세 요.
1)의존 주입:views,extras,시스템 서비스,자원 주입...
2)스 레 드 모드 간소화:방법 에 설명 을 추가 하여 이 방법 이 UI 스 레 드 에서 실행 되 는 지,하위 스 레 드 에서 실행 되 는 지 확인한다.
3)이벤트 바 인 딩:방법 에 설명 을 추가 하여 views 의 그 사건 을 처리 하 는 방법 을 만 듭 니 다.
4),REST client:client 의 인 터 페 이 스 를 만 들 고 AndroidAnnotations 는 실현 코드 를 생 성 합 니 다.이것 은 네트워크 에 관 한 것 입 니 다.
5)명확 하 다:AndroidAnnotations 는 컴 파일 할 때 자동 으로 대응 하 는 하위 클래스 를 생 성 합 니 다.우 리 는 해당 하 는 하위 클래스 를 보고 프로그램 이 어떻게 작 동 하 는 지 알 수 있 습 니 다.
XUtils 프레임 워 크 분석
    xutils 프레임 워 크 는 우리 가 지금 사용 하고 있 는 프레임 워 크 입 니 다.그러면 그의 주해 기능 을 분석 해 보 겠 습 니 다.xutils 의 사용 방식 은 Butterknife 와 마찬가지 로 구성원 변수,방법 에 설명 을 추가 한 다음 에 하나의 방법(xutils 는 ViewUtils.inject()방법)을 호출 하여 구성원 변수 에 값 을 부여 하고 이벤트 방법 을 view 에 설정 합 니 다.다른 것 은 Butterknife 는 자동 으로 생 성 된 코드 를 호출 하여 값 을 부여 하고 xutils 는 반 사 를 통 해 이 루어 집 니 다.ok,소스 코드 로 말 해 봐.

private static void injectObject(Object handler, ViewFinder finder) {

  Class<?> handlerType = handler.getClass();

  // inject ContentView
  .......

  // inject view
  Field[] fields = handlerType.getDeclaredFields();
  if (fields != null && fields.length > 0) {
   for (Field field : fields) {
    ViewInject viewInject = field.getAnnotation(ViewInject.class);
    if (viewInject != null) {
     try {
      View view = finder.findViewById(viewInject.value(), viewInject.parentId());
      if (view != null) {
       field.setAccessible(true);
       field.set(handler, view);
      }
     } catch (Throwable e) {
      LogUtils.e(e.getMessage(), e);
     }
    } else {
     ResInject resInject = field.getAnnotation(ResInject.class);
     ...... //  viewInject  
     } else {
      PreferenceInject preferenceInject = field.getAnnotation(PreferenceInject.class);
      ...... //  viewInject  
     }
    }
   }
  }

  // inject event
  Method[] methods = handlerType.getDeclaredMethods();
  if (methods != null && methods.length > 0) {
   for (Method method : methods) {
    Annotation[] annotations = method.getDeclaredAnnotations();
    if (annotations != null && annotations.length > 0) {
     for (Annotation annotation : annotations) {
      Class<?> annType = annotation.annotationType();
      if (annType.getAnnotation(EventBase.class) != null) {
       method.setAccessible(true);
       try {
        // ProGuard:-keep class * extends java.lang.annotation.Annotation { *; }
        Method valueMethod = annType.getDeclaredMethod("value");
        Method parentIdMethod = null;
        try {
         parentIdMethod = annType.getDeclaredMethod("parentId");
        } catch (Throwable e) {
        }
        Object values = valueMethod.invoke(annotation);
        Object parentIds = parentIdMethod == null ? null : parentIdMethod.invoke(annotation);
        int parentIdsLen = parentIds == null ? 0 : Array.getLength(parentIds);
        int len = Array.getLength(values);
        for (int i = 0; i < len; i++) {
         ViewInjectInfo info = new ViewInjectInfo();
         info.value = Array.get(values, i);
         info.parentId = parentIdsLen > i ? (Integer) Array.get(parentIds, i) : 0;
         EventListenerManager.addEventMethod(finder, info, annotation, handler, method);
        }
       } catch (Throwable e) {
        LogUtils.e(e.getMessage(), e);
       }
      }
     }
    }
   }
  }
 }

    반사 되 고 반사 되 는 것 을 볼 수 있 습 니 다.현재 의 반사 속도 도 매우 빠 르 지만 원생 코드 에 비해 주석 을 많이 사용 하면 초기 화 속도 가 점점 느 려 집 니 다.위의 주석 처리 코드 를 통 해 알 수 있 듯 이 xutils 가 지원 하 는 주석 은 현재 UI,자원,이벤트,Shared Preference 바 인 딩 이 있 습 니 다.xutils 와 마찬가지 로 실행 할 때 반 사 를 이용 하여 주석 을 해석 하 는 프레임 워 크 는 afinal,roboguice 등 이 있 습 니 다.
      시장 에는 또 다른 주석 프레임 워 크 가 많 지만 그 종 류 를 떠 나 지 않 고 반사 가 아니면 자동 으로 코드 를 생 성 한다.반사 기능 은 강하 지만 바람 직 하지 않 아 속 도 를 늦 출 뿐만 아니 라 프로그램의 패 키 징 도 깨 뜨 릴 수 있다.개인 적 으로 코드 를 만 드 는 방안 이 비교적 좋다 고 생각 합 니 다.모든 기능 을 컴 파일 할 때 했 기 때문에 사용자 의 체험 에 영향 을 주지 않 습 니 다.유일한 단점 은 반사 보다 실현 하기 어렵 다 는 것 입 니 다.그러나 우리 프로그램 은 어려움 을 자신 에 게 남 겨 두 고 즐거움 을 사용자 에 게 남 겨 주 는 것 이 아 닙 니까?
     마지막 으로 위의 세 가지 틀 을 정리 해 보 자.

위의 어려움,강약,속 도 는 모두 그들 세 사람 에 게 있 는 것 이다.예 를 들 어 AndroidAnnotations 의 접속 평가 가 어렵 다 는 것 은 그의 접속 방식 이 어렵 다 는 것 을 의미 하지 않 는 다.다만 ButterKnife 와 XUtils 에 비해 그들 보다 어렵다.UI 바 인 딩,자원 바 인 딩,이벤트 바 인 딩 기능 만 사용 하려 면 ButterKnife 를 추천 합 니 다.이상 의 분석 은 순 전 히 개인 적 인 관점 이 므 로 참고 하 시기 바 랍 니 다!
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기