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

深入分析安卓(Android)中的注解

 更新時(shí)間:2016年08月15日 14:49:14   投稿:daisy  
注解是我們經(jīng)常接觸的技術(shù),Java有注解,Android也有注解,本文將試圖介紹Android中的注解,以及ButterKnife和Otto這些基于注解的庫(kù)的一些工作原理.下面一起來(lái)看看。

歸納而言,Android中的注解大概有以下好處

      1、提高我們的開(kāi)發(fā)效率

      2、更早的發(fā)現(xiàn)程序的問(wèn)題或者錯(cuò)誤

      3、更好的增加代碼的描述能力

      4、更加利于我們的一些規(guī)范約束

      5、提供解決問(wèn)題的更優(yōu)解

準(zhǔn)備工作

默認(rèn)情況下,Android中的注解包并沒(méi)有包括在framework中,它獨(dú)立成一個(gè)單獨(dú)的包,通常我們需要引入這個(gè)包.

dependencies {
  compile 'com.android.support:support-annotations:22.2.0'
}

但是如果我們已經(jīng)引入了 appcompat 則沒(méi)有必要再次引用 support-annotations ,因?yàn)?appcompat 默認(rèn)包含了對(duì)其引用.

替代枚舉

在最早的時(shí)候,當(dāng)我們想要做一些值得限定實(shí)現(xiàn)枚舉的效果,通常是

      1、定義幾個(gè)常量用于限定

      2、從上面的常量選取值進(jìn)行使用

一個(gè)比較描述上面問(wèn)題的示例代碼如下

public static final int COLOR_RED = 0;
public static final int COLOR_GREEN = 1;
public static final int COLOR_YELLOW = 2;

public void setColor(int color) {
  //some code here
}
//調(diào)用
setColor(COLOR_RED)

然而上面的還是有不盡完美的地方

      1、setColor(COLOR_RED) 與 setColor(0) 效果一樣,而后者可讀性很差,但卻可以正常運(yùn)行

      2、setColor方法可以接受枚舉之外的值,比如 setColor(3) ,這種情況下程序可能出問(wèn)題

一個(gè)相對(duì)較優(yōu)的解決方法就是使用Java中的Enum.使用枚舉實(shí)現(xiàn)的效果如下

// ColorEnum.java
public enum ColorEmun {
  RED,
  GREEN,
  YELLOW
}

public void setColorEnum(ColorEmun colorEnum) {
  //some code here
}

setColorEnum(ColorEmun.GREEN);

然而Enum也并非最佳,Enum因?yàn)槠湎啾确桨敢坏某A縼?lái)說(shuō),占用內(nèi)存相對(duì)大很多而受到曾經(jīng)被Google列為不建議使用,為此Google特意引入了一些相關(guān)的注解來(lái)替代枚舉.

Android中新引入的替代枚舉的注解有 IntDef 和 StringDef ,這里以 IntDef 做例子說(shuō)明一下.

public class Colors {
  @IntDef({RED, GREEN, YELLOW})
  @Retention(RetentionPolicy.SOURCE)
  public @interface LightColors{}

  public static final int RED = 0;
  public static final int GREEN = 1;
  public static final int YELLOW = 2;
}

      1、聲明必要的int常量

      2、聲明一個(gè)注解為L(zhǎng)ightColors

      3、使用@IntDef修飾LightColors,參數(shù)設(shè)置為待枚舉的集合

      4、使用@Retention(RetentionPolicy.SOURCE)指定注解僅存在與源碼中,不加入到class文件中

Null相關(guān)的注解

和Null相關(guān)的注解有兩個(gè)

       @Nullable 注解的元素可以是Null

       @NonNull 注解的元素不能是Null

上面的兩個(gè)可以修飾如下的元素

       1、成員屬性

       2、方法參數(shù)

       3、方法的返回值

@Nullable
private String obtainReferrerFromIntent(@NonNull Intent intent) {
  return intent.getStringExtra("apps_referrer");
}

NonNull檢測(cè)生效的條件

      1、顯式傳入null

      2、在調(diào)用方法之前已經(jīng)判斷了參數(shù)為null時(shí)

setReferrer(null);//提示警告

//不提示警告
String referrer = getIntent().getStringExtra("apps_referrer");
setReferrer(referrer);

//提示警告
String referrer = getIntent().getStringExtra("apps_referrer");
if (referrer == null) {
  setReferrer(referrer);
}

private void setReferrer(@NonNull String referrer) {
  //some code here
}

區(qū)間范圍注解

Android中的IntRange和FloatRange是兩個(gè)用來(lái)限定區(qū)間范圍的注解,

float currentProgress;

public void setCurrentProgress(@FloatRange(from=0.0f, to=1.0f) float progress) {
  currentProgress = progress;
}

如果我們傳入非法的值,如下所示

setCurrentProgress(11);

就會(huì)得到這樣的錯(cuò)誤

Value must be >=0.0 and <= 1.0(was 11)

長(zhǎng)度以及數(shù)組大小限制

限制字符串的長(zhǎng)度

private void setKey(@Size(6) String key) {
}

限定數(shù)組集合的大小

private void setData(@Size(max = 1) String[] data) {
}
setData(new String[]{"b", "a"});//error occurs

限定特殊的數(shù)組長(zhǎng)度,比如3的倍數(shù)

private void setItemData(@Size(multiple = 3) String[] data) {
}

權(quán)限相關(guān)

在Android中,有很多場(chǎng)景都需要使用權(quán)限,無(wú)論是Marshmallow之前還是之后的動(dòng)態(tài)權(quán)限管理.都需要在manifest中進(jìn)行聲明,如果忘記了,則會(huì)導(dǎo)致程序崩潰. 好在有一個(gè)注解能輔助我們避免這個(gè)問(wèn)題.使用RequiresPermission注解即可.

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
  public void changeWallpaper(Bitmap bitmap) throws IOException {
}

資源注解

在Android中幾乎所有的資源都可以有對(duì)應(yīng)的資源id.比如獲取定義的字符串,我們可以通過(guò)下面的方法

public String getStringById(int stringResId) {
  return getResources().getString(stringResId);
}

使用這個(gè)方法,我們可以很容易的獲取到定義的字符串,但是這樣的寫法也存在著風(fēng)險(xiǎn).

 getStringById(R.mipmap.ic_launcher)

如果我們?cè)诓恢榛蛘呤韬銮闆r下,傳入這樣的值,就會(huì)出現(xiàn)問(wèn)題. 但是如果我們使用資源相關(guān)的注解修飾了參數(shù),就能很大程度上避免錯(cuò)誤的情況.

public String getStringById(@StringRes int stringResId) {
  return getResources().getString(stringResId);
}

在Android中資源注解如下所示

      AnimRes

      AnimatorRes

      AnyRes

      ArrayRes

      AttrRes

      BoolRes

      ColorRes

      DimenRes

      DrawableRes

      FractionRes

      IdRes

      IntegerRes

      InterpolatorRes

      LayoutRes

      MenuRes

      PluralsRes

      RawRes

      StringRes

      StyleRes

      StyleableRes

      TransitionRes

      XmlRes

Color值限定

上面部分提到了 ColorRes ,用來(lái)限定顏色資源id,這里我們將使用 ColorInt ,一個(gè)用來(lái)限定Color值的注解. 在較早的TextView的setTextColor是這樣實(shí)現(xiàn)的.

public void setTextColor(int color) {
  mTextColor = ColorStateList.valueOf(color);
  updateTextColors();
}

然而上面的方法在調(diào)用時(shí)常常會(huì)出現(xiàn)這種情況

myTextView.setTextColor(R.color.colorAccent);

如上,如果傳遞過(guò)去的參數(shù)為color的資源id就會(huì)出現(xiàn)顏色取錯(cuò)誤的問(wèn)題,這個(gè)問(wèn)題在過(guò)去還是比較嚴(yán)重的.好在 ColorInt 出現(xiàn)了,改變了這一問(wèn)題.

public void setTextColor(@ColorInt int color) {
  mTextColor = ColorStateList.valueOf(color);
  updateTextColors();
}

當(dāng)我們?cè)俅蝹魅隒olor資源值時(shí),就會(huì)得到錯(cuò)誤的提示.

CheckResult

這是一個(gè)關(guān)于返回結(jié)果的注解,用來(lái)注解方法,如果一個(gè)方法得到了結(jié)果,卻沒(méi)有使用這個(gè)結(jié)果,就會(huì)有錯(cuò)誤出現(xiàn),一旦出現(xiàn)這種錯(cuò)誤,就說(shuō)明你沒(méi)有正確使用該方法。

@CheckResult
public String trim(String s) {
  return s.trim();
}

線程相關(guān)

Android中提供了四個(gè)與線程相關(guān)的注解

      @UiThread,通??梢缘韧谥骶€程,標(biāo)注方法需要在UIThread執(zhí)行,比如View類就使用這個(gè)注解

      @MainThread 主線程,經(jīng)常啟動(dòng)后創(chuàng)建的第一個(gè)線程

      @WorkerThread 工作者線程,一般為一些后臺(tái)的線程,比如AsyncTask里面的doInBackground就是這樣的.

      @BinderThread 注解方法必須要在BinderThread線程中執(zhí)行,一般使用較少.

一些示例

new AsyncTask<Void, Void, Void>() {
    //doInBackground is already annotated with @WorkerThread
    @Override
    protected Void doInBackground(Void... params) {
      return null;
      updateViews();//error
    }
  };

@UiThread
public void updateViews() {
  Log.i(LOGTAG, "updateViews ThreadInfo=" + Thread.currentThread());
}

注意,這種情況下不會(huì)出現(xiàn)錯(cuò)誤提示

new Thread(){
  @Override
  public void run() {
    super.run();
    updateViews();
  }
}.start();

雖然updateViews會(huì)在一個(gè)新的工作者線程中執(zhí)行,但是在compile時(shí)沒(méi)有錯(cuò)誤提示.

因?yàn)樗呐袛嘁罁?jù)是,如果updateView的線程注解(這里為@UiThread)和run(沒(méi)有線程注解)不一致才會(huì)錯(cuò)誤提示.如果run方法沒(méi)有線程注解,則不提示.

CallSuper

重寫的方法必須要調(diào)用super方法

使用這個(gè)注解,我們可以強(qiáng)制方法在重寫時(shí)必須調(diào)用父類的方法 比如Application的 onCreate , onConfigurationChanged 等.

Keep

在Android編譯生成APK的環(huán)節(jié),我們通常需要設(shè)置minifyEnabled為true實(shí)現(xiàn)下面的兩個(gè)效果

      1、混淆代碼

      2、刪除沒(méi)有用的代碼

但是出于某一些目的,我們需要不混淆某部分代碼或者不刪除某處代碼,除了配置復(fù)雜的Proguard文件之外,我們還可以使用@Keep注解 .

@Keep
public static int getBitmapWidth(Bitmap bitmap) {
  return bitmap.getWidth();
}

ButterKnife

ButterKnife是一個(gè)用來(lái)綁定View,資源和回調(diào)的提高效率的工具.作者為Jake Wharton. ButterKnife的好處

       1、使用BindView替代繁瑣的findViewById和類型轉(zhuǎn)換

       2、使用OnClick注解方法來(lái)替換顯式聲明的匿名內(nèi)部類

      3、使用BindString,BindBool,BindDrawable等注解實(shí)現(xiàn)資源獲取

一個(gè)摘自Github的示例

class ExampleActivity extends Activity {
 @BindView(R.id.user) EditText username;
 @BindView(R.id.pass) EditText password;

 @BindString(R.string.login_error) String loginErrorMessage;

 @OnClick(R.id.submit) void submit() {
  // TODO call server...
 }

 @Override public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.simple_activity);
  ButterKnife.bind(this);
  // TODO Use fields...
 }
}

ButterKnife工作原理

以BindView注解使用為例,示例代碼為

public class MainActivity extends AppCompatActivity {
  @BindView(R.id.myTextView)
  TextView myTextView;

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

1.程序在compile時(shí),會(huì)根據(jù)注解自動(dòng)生成兩個(gè)類,這里為 MainActivity_ViewBinder.class MainActivity_ViewBinding.class

2.當(dāng)我們調(diào)用 ButterKnife.bind(this); 時(shí),會(huì)查找當(dāng)前類對(duì)應(yīng)的ViewBinder類,并調(diào)用bind方法,這里會(huì)調(diào)用到 MainActiivty_ViewBinder.bind 方法.

3.MainActiivty_ViewBinder.bind方法實(shí)際上是調(diào)用了findViewById然后在進(jìn)行類型轉(zhuǎn)換,賦值給MainActivitymyTextView屬性

ButterKnife的bind方法

public static Unbinder bind(@NonNull Activity target) {
  return getViewBinder(target).bind(Finder.ACTIVITY, target, target);
}

ButterKnife的 getViewBinder 和 findViewBinderForClass

@NonNull @CheckResult @UiThread
 static ViewBinder<Object> getViewBinder(@NonNull Object target) {
  Class<?> targetClass = target.getClass();
  if (debug) Log.d(TAG, "Looking up view binder for " + targetClass.getName());
  return findViewBinderForClass(targetClass);
 }

 @NonNull @CheckResult @UiThread
 private static ViewBinder<Object> findViewBinderForClass(Class<?> cls) {
  //如果內(nèi)存集合BINDERS中包含,則不再查找
  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.") || clsName.startsWith("java.")) {
   if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
   return NOP_VIEW_BINDER;
  }
  //noinspection TryWithIdenticalCatches Resolves to API 19+ only type.
  try {
   //使用反射創(chuàng)建實(shí)例
   Class<?> viewBindingClass = Class.forName(clsName + "_ViewBinder");
   //noinspection unchecked
   viewBinder = (ViewBinder<Object>) viewBindingClass.newInstance();
   if (debug) Log.d(TAG, "HIT: Loaded view binder class.");
  } catch (ClassNotFoundException e) {
    //如果沒(méi)有找到,對(duì)父類進(jìn)行查找
   if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());
   viewBinder = findViewBinderForClass(cls.getSuperclass());
  } catch (InstantiationException e) {
   throw new RuntimeException("Unable to create view binder for " + clsName, e);
  } catch (IllegalAccessException e) {
   throw new RuntimeException("Unable to create view binder for " + clsName, e);
  }
  //加入內(nèi)存集合,便于后續(xù)的查找
  BINDERS.put(cls, viewBinder);
  return viewBinder;
 }

MainActivity_ViewBinder的反編譯源碼

➜ androidannotationsample javap -c MainActivity_ViewBinder
Warning: Binary file MainActivity_ViewBinder contains com.example.admin.androidannotationsample.MainActivity_ViewBinder
Compiled from "MainActivity_ViewBinder.java"
public final class com.example.admin.androidannotationsample.MainActivity_ViewBinder implements butterknife.internal.ViewBinder<com.example.admin.androidannotationsample.MainActivity> {
 public com.example.admin.androidannotationsample.MainActivity_ViewBinder();
  Code:
    0: aload_0
    1: invokespecial #1         // Method java/lang/Object."<init>":()V
    4: return

 public butterknife.Unbinder bind(butterknife.internal.Finder, com.example.admin.androidannotationsample.MainActivity, java.lang.Object);
  Code:
    0: new      #2         // class com/example/admin/androidannotationsample/MainActivity_ViewBinding
    3: dup
    4: aload_2
    5: aload_1
    6: aload_3              // 創(chuàng)建ViewBinding實(shí)例
    7: invokespecial #3         // Method com/example/admin/androidannotationsample/MainActivity_ViewBinding."<init>":(Lcom/example/admin/androidannotationsample/MainActivity;Lbutterknife/internal/Finder;Ljava/lang/Object;)V
   10: areturn

 public butterknife.Unbinder bind(butterknife.internal.Finder, java.lang.Object, java.lang.Object);
  Code:
    0: aload_0
    1: aload_1
    2: aload_2
    3: checkcast   #4         // class com/example/admin/androidannotationsample/MainActivity
    6: aload_3              //調(diào)用上面的重載方法
    7: invokevirtual #5         // Method bind:(Lbutterknife/internal/Finder;Lcom/example/admin/androidannotationsample/MainActivity;Ljava/lang/Object;)Lbutterknife/Unbinder;
   10: areturn
}

MainActivity_ViewBinding的反編譯源碼

➜ androidannotationsample javap -c MainActivity_ViewBinding
Warning: Binary file MainActivity_ViewBinding contains com.example.admin.androidannotationsample.MainActivity_ViewBinding
Compiled from "MainActivity_ViewBinding.java"
public class com.example.admin.androidannotationsample.MainActivity_ViewBinding<T extends com.example.admin.androidannotationsample.MainActivity> implements butterknife.Unbinder {
 protected T target;

 public com.example.admin.androidannotationsample.MainActivity_ViewBinding(T, butterknife.internal.Finder, java.lang.Object);
  Code:
    0: aload_0
    1: invokespecial #1         // Method java/lang/Object."<init>":()V
    4: aload_0
    5: aload_1
    6: putfield   #2         // Field target:Lcom/example/admin/androidannotationsample/MainActivity;
    9: aload_1
   10: aload_2
   11: aload_3              //調(diào)用Finder.findRequireViewAsType找到View,并進(jìn)行類型轉(zhuǎn)換,并復(fù)制給MainActivity中對(duì)一個(gè)的變量
   12: ldc      #4         // int 2131427412
   14: ldc      #5         // String field 'myTextView'
   16: ldc      #6         // class android/widget/TextView
                      // 內(nèi)部實(shí)際調(diào)用了findViewById
   18: invokevirtual #7         // Method butterknife/internal/Finder.findRequiredViewAsType:(Ljava/lang/Object;ILjava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
   21: checkcast   #6         // class android/widget/TextView
   24: putfield   #8         // Field com/example/admin/androidannotationsample/MainActivity.myTextView:Landroid/widget/TextView;
   27: return

 public void unbind();
  Code:
    0: aload_0
    1: getfield   #2         // Field target:Lcom/example/admin/androidannotationsample/MainActivity;
    4: astore_1
    5: aload_1
    6: ifnonnull   19
    9: new      #9         // class java/lang/IllegalStateException
   12: dup
   13: ldc      #10         // String Bindings already cleared.
   15: invokespecial #11         // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
   18: athrow
   19: aload_1
   20: aconst_null            // 解除綁定,設(shè)置對(duì)應(yīng)的變量為null
   21: putfield   #8         // Field com/example/admin/androidannotationsample/MainActivity.myTextView:Landroid/widget/TextView;
   24: aload_0
   25: aconst_null
   26: putfield   #2         // Field target:Lcom/example/admin/androidannotationsample/MainActivity;
   29: return
}

Finder的源碼

package butterknife.internal;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.support.annotation.IdRes;
import android.view.View;

@SuppressWarnings("UnusedDeclaration") // Used by generated code.
public enum Finder {
 VIEW {
  @Override public View findOptionalView(Object source, @IdRes int id) {
   return ((View) source).findViewById(id);
  }

  @Override public Context getContext(Object source) {
   return ((View) source).getContext();
  }

  @Override protected String getResourceEntryName(Object source, @IdRes int id) {
   final View view = (View) source;
   // In edit mode, getResourceEntryName() is unsupported due to use of BridgeResources
   if (view.isInEditMode()) {
    return "<unavailable while editing>";
   }
   return super.getResourceEntryName(source, id);
  }
 },
 ACTIVITY {
  @Override public View findOptionalView(Object source, @IdRes int id) {
   return ((Activity) source).findViewById(id);
  }

  @Override public Context getContext(Object source) {
   return (Activity) source;
  }
 },
 DIALOG {
  @Override public View findOptionalView(Object source, @IdRes int id) {
   return ((Dialog) source).findViewById(id);
  }

  @Override public Context getContext(Object source) {
   return ((Dialog) source).getContext();
  }
 };

 //查找對(duì)應(yīng)的Finder,如上面的ACTIVITY, DIALOG, VIEW
 public abstract View findOptionalView(Object source, @IdRes int id);


 public final <T> T findOptionalViewAsType(Object source, @IdRes int id, String who,
   Class<T> cls) {
  View view = findOptionalView(source, id);
  return castView(view, id, who, cls);
 }

 public final View findRequiredView(Object source, @IdRes int id, String who) {
  View view = findOptionalView(source, id);
  if (view != null) {
   return view;
  }
  String name = getResourceEntryName(source, id);
  throw new IllegalStateException("Required view '"
    + name
    + "' with ID "
    + id
    + " for "
    + who
    + " was not found. If this view is optional add '@Nullable' (fields) or '@Optional'"
    + " (methods) annotation.");
 }

 //來(lái)自ViewBinding的調(diào)用
 public final <T> T findRequiredViewAsType(Object source, @IdRes int id, String who,
   Class<T> cls) {
  View view = findRequiredView(source, id, who);
  return castView(view, id, who, cls);
 }

 public final <T> T castView(View view, @IdRes int id, String who, Class<T> cls) {
  try {
   return cls.cast(view);
  } catch (ClassCastException e) {
   String name = getResourceEntryName(view, id);
   throw new IllegalStateException("View '"
     + name
     + "' with ID "
     + id
     + " for "
     + who
     + " was of the wrong type. See cause for more info.", e);
  }
 }

 @SuppressWarnings("unchecked") // That's the point.
 public final <T> T castParam(Object value, String from, int fromPos, String to, int toPos) {
  try {
   return (T) value;
  } catch (ClassCastException e) {
   throw new IllegalStateException("Parameter #"
     + (fromPos + 1)
     + " of method '"
     + from
     + "' was of the wrong type for parameter #"
     + (toPos + 1)
     + " of method '"
     + to
     + "'. See cause for more info.", e);
  }
 }

 protected String getResourceEntryName(Object source, @IdRes int id) {
  return getContext(source).getResources().getResourceEntryName(id);
 }

 public abstract Context getContext(Object source);
}

Otto

Otto Bus 是一個(gè)專為Android改裝的Event Bus,在很多項(xiàng)目中都有應(yīng)用.由Square開(kāi)源共享.

public class EventBusTest {
  private static final String LOGTAG = "EventBusTest";
  Bus mBus = new Bus();

  public void test() {
    mBus.register(this);
  }

  class NetworkChangedEvent {

  }

  @Produce
  public NetworkChangedEvent sendNetworkChangedEvent() {
    return new NetworkChangedEvent();
  }


  @Subscribe
  public void onNetworkChanged(NetworkChangedEvent event) {
    Log.i(LOGTAG, "onNetworkChanged event=" + event);
  }
}

Otto 的工作原理

      1、使用@Produce和@Subscribe標(biāo)記方法

      2、當(dāng)調(diào)用bus.register方法,去檢索注冊(cè)對(duì)象的標(biāo)記方法,并cache映射關(guān)系

      3、當(dāng)post事件時(shí),將事件與handler方法對(duì)應(yīng)加入事件隊(duì)列

      4、抽取事件隊(duì)列,然后調(diào)用handler處理

如下為對(duì)Otto如何利用注解的分析

register的源碼

public void register(Object object) {
  if (object == null) {
   throw new NullPointerException("Object to register must not be null.");
  }
  enforcer.enforce(this);
  //查找object中的Subscriber
  Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);
  for (Class<?> type : foundHandlersMap.keySet()) {
   Set<EventHandler> handlers = handlersByType.get(type);
   if (handlers == null) {
    //concurrent put if absent
    Set<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();
    handlers = handlersByType.putIfAbsent(type, handlersCreation);
    if (handlers == null) {
      handlers = handlersCreation;
    }
   }
   final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);
   if (!handlers.addAll(foundHandlers)) {
    throw new IllegalArgumentException("Object already registered.");
   }
  }

  for (Map.Entry<Class<?>, Set<EventHandler>> entry : foundHandlersMap.entrySet()) {
   Class<?> type = entry.getKey();
   EventProducer producer = producersByType.get(type);
   if (producer != null && producer.isValid()) {
    Set<EventHandler> foundHandlers = entry.getValue();
    for (EventHandler foundHandler : foundHandlers) {
     if (!producer.isValid()) {
      break;
     }
     if (foundHandler.isValid()) {
      dispatchProducerResultToHandler(foundHandler, producer);
     }
    }
   }
  }
 }

HandlerFinder源碼

interface HandlerFinder {

 Map<Class<?>, EventProducer> findAllProducers(Object listener);

 Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener);

 //Otto注解查找器
 HandlerFinder ANNOTATED = new HandlerFinder() {
  @Override
  public Map<Class<?>, EventProducer> findAllProducers(Object listener) {
   return AnnotatedHandlerFinder.findAllProducers(listener);
  }

  @Override
  public Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
   return AnnotatedHandlerFinder.findAllSubscribers(listener);
  }
 };

具體查找實(shí)現(xiàn)

/** This implementation finds all methods marked with a {@link Subscribe} annotation. */
 static Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
  Class<?> listenerClass = listener.getClass();
  Map<Class<?>, Set<EventHandler>> handlersInMethod = new HashMap<Class<?>, Set<EventHandler>>();

  Map<Class<?>, Set<Method>> methods = SUBSCRIBERS_CACHE.get(listenerClass);
  if (null == methods) {
   methods = new HashMap<Class<?>, Set<Method>>();
   loadAnnotatedSubscriberMethods(listenerClass, methods);
  }
  if (!methods.isEmpty()) {
   for (Map.Entry<Class<?>, Set<Method>> e : methods.entrySet()) {
    Set<EventHandler> handlers = new HashSet<EventHandler>();
    for (Method m : e.getValue()) {
     handlers.add(new EventHandler(listener, m));
    }
    handlersInMethod.put(e.getKey(), handlers);
   }
  }

  return handlersInMethod;
 }

總結(jié)

以上就是關(guān)于Android中注解的一些總結(jié),文章部分內(nèi)容參考自 Support Annotations ,希望能幫助大家對(duì)注解有基礎(chǔ)的認(rèn)識(shí),并運(yùn)用到實(shí)際的日常開(kāi)發(fā)之中。如有有疑問(wèn)歡迎大家留言討論。

相關(guān)文章

最新評(píng)論