欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android注解框架對(duì)比分析

 更新時(shí)間:2017年02月04日 16:15:52   作者:幸福過(guò)飽和  
這篇文章主要為大家詳細(xì)對(duì)比分析了Android注解框架,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

Java的注解(Annotation)相當(dāng)于一種標(biāo)記,在程序中加入注解就等于為程序打上某種標(biāo)記,標(biāo)記可以加在包,類,屬性,方法,本地變量上。然后你可以寫一個(gè)注解處理器去解析處理這些注解(人稱編譯時(shí)注解),也可以在程序運(yùn)行時(shí)利用反射得到注解做出相應(yīng)的處理(人稱運(yùn)行時(shí)注解)。

開(kāi)發(fā)Android程序時(shí),沒(méi)完沒(méi)了的findViewById, setOnClickListener等等方法,已經(jīng)讓大多數(shù)開(kāi)發(fā)者頭疼不已。好在市面上有所謂的注解框架可以幫助開(kāi)發(fā)者簡(jiǎn)化一些過(guò)程。比較流行的有butterknife, annotations, xutils, afinal, roboguice等等。今天我們就來(lái)對(duì)比一下這些注解框架。

ButterKnife框架分析

       首先看下Butterknife,來(lái)自Jakewharton大神的力作,特點(diǎn)是接入簡(jiǎn)單,依賴一個(gè)庫(kù)就好了。另外在Android Studio上還有提供一個(gè)插件,自動(dòng)生成注解與類屬性。

       Butterknife目前支持的注解有: View綁定(Bind),資源綁定(BindBool, BindColor, BindDimen, BindDrawble, BindInt, BindString),事件綁定(OnCheckedChanged, OnClick, OnEditorAction, OnFocusChange, OnItemClick, OnItemLongClick, OnItemSelected, OnLongClick, OnPageChange, OnTextChanged, OnTouch)。

       Butterknife的原理是運(yùn)行時(shí)注解。先來(lái)看下一個(gè)demo。

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已經(jīng)得到了控件的索引");
 }

 @OnClick(R.id.tv2)
 public void tv2OnClick() {
  Toast.makeText(this, "tv2被點(diǎn)擊了", Toast.LENGTH_SHORT).show();
 }

這是一個(gè)View綁定的例子,你需要在成員變量上注解需要綁定的控件id,然后再調(diào)用ButterKnife.bind(Activity target)方法對(duì)帶注解的成員變量進(jìn)行賦值。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);
 }

由上面代碼可以看出,最終需要調(diào)用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);
 }
 }

這個(gè)方法就是尋找或者生成對(duì)應(yīng)的 ViewBinder對(duì)象,然后調(diào)用該對(duì)象的bind(Finder finder, T target, Object source)方法為被注解的變量賦值。先看下findViewBinderForClass(Class<?> cls)方法。

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;
 }

       可以看出是利用反射生成一個(gè)ViewBinder對(duì)象出來(lái),而且還帶有緩存,也就是說(shuō),同一個(gè)class多次調(diào)用只會(huì)反射一次。反射雖然比原生代碼慢一些,但是如果只有一次反射的話,對(duì)性能的影響完全可以忽略不計(jì)。那現(xiàn)在的問(wèn)題就是這個(gè)反射生成的ViewBinder是什么東西, 它的bind(Finder finder, T target, Object source) 方法是如何為被注解的變量賦值的?
       上面說(shuō)過(guò)Butterknife框架是編譯時(shí)注解,一般這類注解會(huì)在編譯的時(shí)候,根據(jù)注解標(biāo)識(shí),動(dòng)態(tài)生成一些類或者生成一些xml都可以,在運(yùn)行時(shí)期,這類注解是沒(méi)有的~~會(huì)依靠動(dòng)態(tài)生成的類做一些操作,因?yàn)闆](méi)有反射,效率和直接調(diào)用方法沒(méi)什么區(qū)別~~~。在程序編譯時(shí), Butterknife會(huì)跟據(jù)所有的注解生成對(duì)應(yīng)的代碼比如說(shuō)上面的MainActivity類,Butterknife會(huì)生成

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注解到最后就是調(diào)用生成的代碼來(lái)findViewById然后給其賦值的,事件就是給view設(shè)置一個(gè)默認(rèn)的事件,然后里面調(diào)用你注解的那個(gè)方法。所以在性能上,ButterKnife并不會(huì)影響到app。 Butterknife 自動(dòng)生產(chǎn)的代碼也不多,不會(huì)對(duì)程序的包大小有什么影響。

AndroidAnnotations框架分析

      再來(lái)分析下著名的Annotations框架。該框架的原理跟Butterknife一樣,都是在編譯時(shí)生成代碼,不過(guò)annotations并不是生成代碼供對(duì)應(yīng)的類調(diào)用去給帶注解的變量、方法賦值,而是直接生成一個(gè)繼承帶注解的類,這個(gè)類里面有對(duì)變量賦值,對(duì)注解方法調(diào)用的代碼。運(yùn)行時(shí),直接運(yùn)行的是annotations生成的類,而不是我們寫的類。說(shuō)了這么多是不是不太明白,沒(méi)關(guān)系,demo來(lái)了!先看下我們寫的類。

@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();
     }

    }
    );
   }
  }
 }
}

方法調(diào)用鏈:onCreate(Bundle saveInstanceState) ----> setContentView() ----> onViewChangedNotifier_.notifyViewChanged(),而onViewChanagedNotifier_.notifyViewChanged()方法最終會(huì)調(diào)用onViewChanged(HasViews hasViews)方法,在此方法中有對(duì)變量賦值,事件方法設(shè)置的代碼,注意看自動(dòng)生成的類的名字,發(fā)現(xiàn)規(guī)律了吧,就是我們寫的類的名字后面加上一個(gè)'_'符號(hào),現(xiàn)在知道為什么用Annotations框架,我們的AndroidManifest.xml中對(duì)Activity 的配置,Activity的名字要多加一個(gè)'_'符號(hào)了吧。因?yàn)檎嬲虞d的是AndroidAnnotations生成的代碼。寫到這里大家發(fā)現(xiàn)沒(méi),annotations框架里面一個(gè)反射都沒(méi)有,沒(méi)錯(cuò)這個(gè)框架沒(méi)有用到反射,沒(méi)有初始化,所有的工作在編譯時(shí)都做了,不會(huì)對(duì)我們的程序造成任何速度上的影響。

       那Annotations支持哪些注解呢?既然Annotations性能上跟Butterknife差不多,那功能呢?在這里翻譯一下官網(wǎng)的Features.

1)、依賴注入:注入views, extras, 系統(tǒng)服務(wù),資源,...
2)、簡(jiǎn)化線程模式:在方法上添加注釋來(lái)制定該方法是運(yùn)行在UI線程還是子線程。
3)、事件綁定:在方法上添加注釋來(lái)制定該方法處理那些views的那個(gè)事件。
4)、REST client:創(chuàng)建一個(gè)client的接口,AndroidAnnotations會(huì)生成實(shí)現(xiàn)代碼,這是關(guān)于網(wǎng)絡(luò)方面的。
5)、清晰明了:AndroidAnnotations會(huì)在編譯時(shí)自動(dòng)生成對(duì)應(yīng)子類,我們可以查看相應(yīng)的子類來(lái)了解程序是怎么運(yùn)行的。
XUtils框架分析

    xutils框架是我們現(xiàn)在在用的框架,那我們就來(lái)分析一下他的注解功能。xutils的使用方式跟Butterknife一樣,都是在成員變量,方法上添加注釋,然后調(diào)用一個(gè)方法(xutils是ViewUtils.inject()方法)對(duì)成員變量賦值、事件方法設(shè)置到view上。不同的是,Butterknife是調(diào)用自動(dòng)生成的代碼來(lái)賦值,而xutils是通過(guò)反射來(lái)實(shí)現(xiàn)的。ok,拿源碼說(shuō)話。

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);
       }
      }
     }
    }
   }
  }
 }

    可以看到反射、反射到處在反射,雖然現(xiàn)在的反射速度也很快了,但是還是不能跟原生代碼相比,一旦注釋用的多了,這初始化速度會(huì)越來(lái)越慢。通過(guò)上面注釋處理的代碼可以看出,xutils支持的注釋目前主要有UI, 資源,事件,SharedPreference綁定。跟xutils一樣是運(yùn)行時(shí)利用反射去解析注釋的框架還有afinal, roboguice等。

      市面上還有很多其他的注釋框架,但是萬(wàn)變不離其宗,不是反射就是自動(dòng)生成代碼。反射功能雖然強(qiáng)大,但是不可取,不僅會(huì)拖慢速度還會(huì)破話程序的封裝性。個(gè)人認(rèn)為生成代碼的方案比較好,所有的功能都在編譯時(shí)做了,并不會(huì)影響到用戶的體驗(yàn),唯一的缺點(diǎn)就是比反射難實(shí)現(xiàn),不過(guò)我們程序不就是把難處留給自己,把快樂(lè)留給用戶么!

     最后,對(duì)上面三種框架總結(jié)一下。

上面的難易,強(qiáng)弱,快慢都是相對(duì)他們?nèi)齻€(gè)自己來(lái)說(shuō)的,比如AndroidAnnotations的接入評(píng)級(jí)是難,并不代表它的接入方式很難,只是相對(duì)ButterKnife和XUtils來(lái)說(shuō)比他們難。如果只想使用UI綁定,資源綁定,事件綁定的功能,推薦使用ButterKnife。以上分析純屬個(gè)人觀點(diǎn),僅供參考!

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android獲取和讀取短信驗(yàn)證碼的實(shí)現(xiàn)方法

    Android獲取和讀取短信驗(yàn)證碼的實(shí)現(xiàn)方法

    這篇文章主要介紹了Android獲取和讀取短信驗(yàn)證碼的實(shí)現(xiàn)方法,文章內(nèi)容介紹了如何讀取剛收到的短信的相關(guān)內(nèi)容,以及Android獲取短信驗(yàn)證碼的方法,感興趣的小伙伴們可以參考一下
    2016-03-03
  • Android在linux下刷機(jī)教程

    Android在linux下刷機(jī)教程

    android 在linux下刷機(jī),我們只需要下載相應(yīng)的zip包,然后一條命令就可以完成,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2016-09-09
  • android獲取屏幕高度和寬度的實(shí)現(xiàn)方法

    android獲取屏幕高度和寬度的實(shí)現(xiàn)方法

    這篇文章主要介紹了android獲取屏幕高度和寬度的實(shí)現(xiàn)方法,較為詳細(xì)的分析了Android獲取屏幕高度和寬度的原理與實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-01-01
  • Android之PreferenceActivity應(yīng)用詳解(2)

    Android之PreferenceActivity應(yīng)用詳解(2)

    看到很多書中都沒(méi)有對(duì)PreferenceActivity做介紹,而我正好又在項(xiàng)目中用到,所以就把自己的使用的在這總結(jié)一下,也方便日后查找
    2012-11-11
  • EditText監(jiān)聽(tīng)方法,實(shí)時(shí)的判斷輸入多少字符

    EditText監(jiān)聽(tīng)方法,實(shí)時(shí)的判斷輸入多少字符

    在EditText提供了一個(gè)方法addTextChangedListener實(shí)現(xiàn)對(duì)輸入文本的監(jiān)控。本文分享了EditText監(jiān)聽(tīng)方法案例,需要的朋友一起來(lái)看下吧
    2016-12-12
  • Android Content Provider詳解及示例代碼

    Android Content Provider詳解及示例代碼

    本文主要講解Android Content Provider,這里提供相關(guān)文檔資料,并附有實(shí)現(xiàn)代碼和實(shí)現(xiàn)效果圖,有需要的小伙伴可以參考下
    2016-08-08
  • android實(shí)現(xiàn)年齡段選擇器

    android實(shí)現(xiàn)年齡段選擇器

    這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)年齡段選擇器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • java實(shí)現(xiàn)靜默安裝apk

    java實(shí)現(xiàn)靜默安裝apk

    本文給大家分享的是如何實(shí)現(xiàn)偷偷的把一個(gè)安卓apk應(yīng)用安裝到手機(jī)上,而且不顯示確認(rèn)框,主要是通過(guò)反射來(lái)實(shí)現(xiàn),好了,小伙伴們仔細(xì)看下代碼吧,有需要的小伙伴可以參考下。
    2015-04-04
  • Android編程獲取系統(tǒng)隱藏服務(wù)實(shí)現(xiàn)鎖屏的方法

    Android編程獲取系統(tǒng)隱藏服務(wù)實(shí)現(xiàn)鎖屏的方法

    這篇文章主要介紹了Android編程獲取系統(tǒng)隱藏服務(wù)實(shí)現(xiàn)鎖屏的方法,涉及Android關(guān)于廣播,服務(wù),權(quán)限及鎖屏等操作的相關(guān)技巧,需要的朋友可以參考下
    2015-12-12
  • android webview 中l(wèi)ocalStorage無(wú)效的解決方法

    android webview 中l(wèi)ocalStorage無(wú)效的解決方法

    這篇文章主要介紹了android webview 中l(wèi)ocalStorage無(wú)效的解決方法,本文直接給出解決方法實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2015-06-06

最新評(píng)論