Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android注解型框架原理淺析

Android注解型框架原理淺析

編輯:關於Android編程

Android:注解型框架原理淺析:在DataBinding框架出來之前,Android有很多很多注解型框架,但是隨著DataBinding的強勢崛起,大多注解型框架都走投無路了。但是為了更好的了解技術,還是寫了一個小小小的注解模型

作為一名初學者,已經厭煩了findViewById了,有沒有更簡單的辦法去獲取xml文件中的控件實例呢?使用注解就可以了。

注解:我們可以把它理解為是一種標記。通過反射機制+標記就能實現注解型框架了。

activity_main.xml





代碼著實太簡單了,就是定義了id分別為username和password的兩個TextView控件。

我的目標就是:自動獲取控件,並且為id為a的控件增加onClickListener監聽,id為b的控件增加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;
}

這裡定義了四個方法,其實要使用的注解。因為寫了default,所以可以不同時使用者四個注解,viewId是用來獲取控件的,layoutId是為activity設置布局的,onClick是為了設置點擊事件監聽的,onLongClick是為了設置長按事件監聽的。

那我們開始在activity中使用這四個注解

@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() )等等。
作為小白,只知道這麼多了

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved