序文
コンパイル時の注釈と比較して、注釈ランタイムの書き込みがはるかに簡単です、基本的な考え方は、私たちがgetAnnotation注釈ラベルクラスを介して取得するやりたい何かを、コメント記号を書くことです。
A:注釈タグ
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface BindId {
int value() default View.NO_ID;
}
上記の唯一の違いは、@よりへのインタフェースであると、私たちは@に加え、インターフェースの変更で始まる、ビューまたはID注釈にカスタム注釈クラスを使用したものです。今、私たちはその結合機能を実装するために、特定のAPIを書きたいです。
II:検出クラスラベルは、何かをする必要があり
例えば、この場合には、BindID.classを検出し、我々は、ラベルに対処するためにsetContentView、findViewByIdを呼び出す必要性を知っています。
public class BindIdApi {
public static void bindId(Activity obj) {
Class<? extends Activity> cls = obj.getClass();
if (cls.isAnnotationPresent(BindId.class)) {
BindId mId = (BindId) cls.getAnnotation(BindId.class);
int id = mId.value();
try {
Method method = cls.getMethod("setContentView", int.class);
method.setAccessible(true);
method.invoke(obj, id);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(BindId.class)) {
BindId mId = field.getAnnotation(BindId.class);
int id = mId.value();
try {
Method method = cls.getMethod("findViewById", int.class);
method.setAccessible(true);
Object view = method.invoke(obj, id);
field.setAccessible(true);
field.set(obj, view);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
具体的なアイデアは、メソッドを呼び出して、最後に通話を発信する方法を見てするためにリフレクションを使用することです:
第三に、特定の使用
package example.tb.com.tannotation;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
@BindId(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@BindId(R.id.tv)
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BindIdApi.bindId(this);
tv.setText("通过注解ID,运行时注解查找");
}
}
あなたはまた、IDの配列を返すことができ、それは使用することは非常に便利ではない、とサポートは、プライベート変数のために、サポートsetContentViewは、もちろん、あなたもfindViewByIdとsetContentViewエリアに二つの別々のノートに分けることができる(()@IdResはint []値を;)、それは、複数のビューをバインドすることができますように。
次に、クリックイベントのsetOnClickListenerノートを見 - ノートを定義することがまず第一に:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BindOnClick {
int[] value();
}
次のようにノートを処理:
public class BindOnClickApi {
public static void bindOnClick(final Activity obj) {
Class<?> cls = obj.getClass();
//获取当前Activity的所有方法,包括私有
Method methods[] = cls.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
final Method method = methods[i];
if (method.isAnnotationPresent(BindOnClick.class)) {
// 得到这个类的OnClick注解
BindOnClick mOnClick = (BindOnClick) method.getAnnotation(BindOnClick.class);
// 得到注解的值
int[] id = mOnClick.value();
for (int j = 0; j < id.length; j++) {
final View view = obj.findViewById(id[j]);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//反射指定的点击方法
try {
//私有方法需要设置true才能访问
method.setAccessible(true);
method.invoke(obj, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
}
非常に明確に書かれている基本的にコメント。このビューの最初の発見は、クリックイベントアップセットへの呼び出しsetOnClickListenerは、アノテーション付きメソッドが最終的にクリックイベントを実行するために、再び反射を呼び出し、その後、です。最後に、活動のonCreate内でのイベントの結合:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BindIdApi.bindId2(this);
BindOnClick.bindOnClick(this);
tv.setText("通过注解ID,运行时注解查找");
}
@OnClick(R.id.tv)
private void click(View view){
switch (view.getId()){
case R.id.tv:
Toast.makeText(this,"annotation",Toast.LENGTH_LONG).show();
break;
}
}
商品コード:
https://github.com/buder-cp/base_component_learn/tree/master/annotation_learn
良い記事に関連する注意事項:
https://mp.weixin.qq.com/s/cZf87Du11cqWD0GF2PmPyw
https://mp.weixin.qq.com/s/ljJ1uBCinBLhCU6MtOApYA