編輯:關於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() )等等。
作為小白,只知道這麼多了
本文參考了manymore13文章邏輯,在此基礎上做了改進:1.可定義最大行數2.定義每行顯示幾張3.當圖片數量過多時設置更多圖片由於個人較懶,去掉了xml配置屬性,所有
首先聲明本文是基於GitHub上baoyongzhang的SwipeMenuListView修改而來,該項目地址:https://github.com/baoyongzh
問題背景:app在上傳圖片時,同時傳遞參數,支持傳遞多個圖片。本文中的環境默認已經配好了服務器的CodeIgniter框架。事實上不使用這個框架也是可以的。 一,服務器部
任何程序都是靜態代碼,我們把這些靜態代碼打包好,然後放到運行環境當中,通過事件流的驅動使這些代碼運行起來。Android的環境也不例外。靜態的代碼,在動態事件的驅動下,才