DataBindingフレームワークが登場する前は、Androidには多くのアノテーションベースのフレームワークがありましたが、DataBindingの大幅な台頭により、ほとんどのアノテーションベースのフレームワークは必死でした。しかし、テクノロジーをよりよく理解するために、私は小さな注釈モデルを作成しました
初心者として、私はfindViewByIdにうんざりしています。xmlファイルでコントロールインスタンスを取得する簡単な方法はありますか?注釈を使用するだけです。
注:マークとして理解できます。アノテーションフレームワークは、リフレクションメカニズム+マークによって実現できます。
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="50dp" />
<TextView
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="50dp" />
</LinearLayout>
コードが単純すぎます。つまり、ユーザー名とパスワードのIDを持つ2つのTextViewコントロールが定義されています。
私の目標は、コントロールを自動的に取得し、ID aのコントロールにonClickListenerを追加し、IDbのコントロールにonLongClickListenerを追加することです。
最初に注釈を定義しましょう
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewAnnotation {
int viewId() default 0;
int layoutId() default 0;
int onClick() default 0;
int onLongClick() default 0;
}
ここでは4つのメソッドが定義されていますが、実際に使用されるアノテーションが使用されます。デフォルトが記述されているため、4つのアノテーションを同時に使用することはできません。viewIdはコントロールの取得に使用され、layoutIdはアクティビティのレイアウトを設定し、onClickはクリックイベントリスナーを設定し、onLongClickは長押しイベントリスナーを設定します。
次に、アクティビティでこれら4つの注釈の使用を開始します
@ViewAnnotation(layoutId = R.layout.activity_main)
public class MainActivity extends Activity {
@ViewAnnotation(viewId = R.id.username)
private TextView username;
@ViewAnnotation(viewId = R.id.password)
private TextView password;
@ViewAnnotation(onClick = R.id.username)
public void clickUsername(View view) {
Toast.makeText(this, "onClickListener", Toast.LENGTH_LONG).show();
}
@ViewAnnotation(onLongClick = R.id.password)
public void onLongClick(View view) {
Toast.makeText(this, "onLongClickListener", Toast.LENGTH_LONG).show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewUtils.injectActivity(this);
username.setText("Aiden");
password.setText("123456");
}
}
ご覧のとおり、コードは非常に単純になっています。onCreate()関数には、ViewUtils.injectActivity(this)が記述されています。これは私のカスタムViewUtilsクラスですが、アノテーション付きのインスタンスを取得したため、findViewByIdは異なります。
public class ViewUtils {
// 注入activity
public static void injectActivity(Activity activity) {
Class<?> activityClass = activity.getClass();
injectContentView(activity, activityClass);
injectView(activity, activityClass);
injectListener(activity, activityClass);
}
// 设置contentView的
private static void injectContentView(Activity activity, Class<?> activityClass) {
if (activityClass.isAnnotationPresent(ViewAnnotation.class)) {
ViewAnnotation inject = activityClass.getAnnotation(ViewAnnotation.class);
int layoutId = inject.layoutId();
if (layoutId > 0) {
activity.setContentView(layoutId);
}
}
}
// 获取控件的
private static void injectView(Activity activity, Class<?> activityClass) {
Field[] fields = activityClass.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(ViewAnnotation.class)) {
field.setAccessible(true);
ViewAnnotation inject = field.getAnnotation(ViewAnnotation.class);
int id = inject.viewId();
if (id > 0) {
try {
field.set(activity, activity.findViewById(id));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
// 分别实现了点击事件和长按事件的监听
private static void injectListener(final Activity activity, Class<?> activityClass) {
Method[] methods = activityClass.getDeclaredMethods();
for (final Method method : methods) {
if (method.isAnnotationPresent(ViewAnnotation.class)) {
ViewAnnotation ViewAnnotation = method.getAnnotation(ViewAnnotation.class);
int onClick = ViewAnnotation.onClick();
if (onClick > 0) {
activity.findViewById(onClick).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
// 回调activity中的方法
method.invoke(activity, v);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
);
}
int onLongClick = ViewAnnotation.onLongClick();
if (onLongClick > 0) {
activity.findViewById(onLongClick).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
try {
// 回调activity中的方法
method.invoke(activity, v);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return false;
}
});
}
}
}
}
}
この時点で、単純な注釈付きフレームワークが形成されます。もちろん、対処する必要のある詳細は他にもあります。たとえば、Fragment、反射制御のその他のメソッド(setAdapter()など)などをサポートします。。。
Xiaobaiとして、私はそんなに知っているだけです