Android快速开发框架之Afinal设计思路分析(一)
来源:互联网 发布:网络雅思课程 编辑:程序博客网 时间:2024/06/06 07:11
Afinal框架内置了四大模块功能:
1. FinalActivity:可通过注解技术为Activity的 View成员变量绑定一个指定id的View,同时也可以为这个View成员注册事件监听器。省去了我们之前使用findViewById()绑定View以及使用setOnXXX()为View注册监听器。尤其是当Activity的View成员比较多的时候,可以为我们省去很多findViewById(),setOnXXX()这样重复的语句,从而减少代码的冗余。
2. FinalDb:通过orm(对象关系映射 Object Relational Mapping)技术,使我们可以一行代码实现对Sqlite数据库的增删改查。且支持一对多,多对一等查询。
3. FinalBitmap:通过使用lru算法管理内存,多线程加载Bitmap,支持缓存并可配置线程数量、缓存大小,缓存路径,无需考虑oom和图片错位现象,可自定义加载动画。
4. FinalHttp:通过HttpClient对http请求进行封装,支持ajax方式加载。
注意事项:使用Afinal快速开发框架需要如下两个权限。
(1)访问网络权限(http请求网络时用)
<uses-permissionandroid:name="android.permission.INTERNET" />
(2)访问sdcard权限(图片缓存时用)
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE" />
一、FinalActivity模块设计思路:
FinalActivity模块的作用就是通过注解为Activity的View类型的成员属性绑定一个View,如果这个View需要某事件监听器则同时为其注册事件监听器。所以设计此模块的思路自然是如何设计注解,并且如何实现View的绑定和事件监听器的注册。
第一步:在项目源代码的根目录下定义FinalActivity类,并且设计成抽象类。
设计成抽象类的目的是为了让继承它的Activity类可以使用FinalActivity模块的功能
public abstract class FinalActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);}}
第二步:在项目源代码的annotation/view包下新建注解,注解中要包含View的id和支持的事件处理方法名。
ViewInject注解:
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)/** * 这是一个注解 ,只能标记在属性字段上,且保留到运行时,说明可以通过反射获取注解的属性值 */public @interface ViewInject { public int id(); //View的id public String click() default "";//点击事件处理方法名,默认为空串 public String longClick() default "";//长按事件处理方法名,默认为空串 public String itemClick() default "";//条目点击事件处理方法名,默认为空串 public String itemLongClick() default "";//条目长近事件处理方法名,默认为空串 public Select select() default @Select(selected="") ;//这里又设计了一个注解,代表条目选中和取消选中方法名,默认选中方法名为空串}
Select注解:
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)/** * 是否被选中的注解 */public @interface Select { public String selected(); //条目选中事件方法名 public String noSelected() default "";//条目取消选中事件方法名,默认为空串 }
第三步:在项目源代码的annotation/view包下设计事件监听总控制类,对外统一使用这个总控制类为View注册事件监听器。(目前Afinal框架只支持点击事件,长按事件,条目点击事件,条目长按事件,条目选中事件,条目取消选中事件)
1、创建EventListener类,实现Afinal支持的几个事件监听器接口,实现各自的抽象方法。
public class EventListener implements View.OnClickListener ,View.OnLongClickListener,AdapterView.OnItemClickListener,AdapterView.OnItemLongClickListener,AdapterView.OnItemSelectedListener{ @Override public void onClick(View v) { } @Override public boolean onLongClick(View v) { return false; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { return false; } @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { } @Override public void onNothingSelected(AdapterView<?> parent) { }}
分析:在设计这个控制类的时候并不知道将来使用者会如何处理各事件,所以这里的实现只是要通过反射获取注册此事件监听器的上下文Activity中用户通过注解指定的事件处理方法,然后回调这个方法。但是反射获取方法是需要方法名的。所以接下来先定义方法名,然后通过这个方法名再反射获取并回调这个方法。
2、定义事件处理方法名,并为其提供set方法,以方便改变其值。
public class EventListener implements View.OnClickListener ,View.OnLongClickListener,AdapterView.OnItemClickListener,AdapterView.OnItemLongClickListener,AdapterView.OnItemSelectedListener{ private String clickMethod;//处理点击事件的方法名 private String longClickMethod; //处理长按事件的方法名 private String itemClickMethod; //处理条目点击事件的方法名 private String itemSelectMethod; //处理条目选中事件的方法名 private String nothingSelectedMethod; //处理条目取消选中事件的方法名 private String itemLongClickMehtod; //处理条目长按事件的方法名 public EventListener click(String method){ this.clickMethod = method; return this; } public EventListener longClick(String method){ this.longClickMethod = method; return this; } public EventListener itemLongClick(String method){ this.itemLongClickMehtod = method; return this; } public EventListener itemClick(String method){ this.itemClickMethod = method; return this; } public EventListener select(String method){ this.itemSelectMethod = method; return this; } public EventListener noSelect(String method){ this.nothingSelectedMethod = method; return this; } @Override public void onClick(View v) { } @Override public boolean onLongClick(View v) { return false; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { return false; } @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { } @Override public void onNothingSelected(AdapterView<?> parent) { }}
3、实现框架层面的各事件处理方法
/** * 事件处理器实现类 */public class EventListener implements OnClickListener, OnLongClickListener, OnItemClickListener, OnItemSelectedListener,OnItemLongClickListener { private Object handler; private String clickMethod; private String longClickMethod; private String itemClickMethod; private String itemSelectMethod; private String nothingSelectedMethod; private String itemLongClickMehtod; /** * 构造器----->传递处理者做为参数 * @param handler */ public EventListener(Object handler) { this.handler = handler; } public EventListener click(String method){ this.clickMethod = method; return this; } public EventListener longClick(String method){ this.longClickMethod = method; return this; } public EventListener itemLongClick(String method){ this.itemLongClickMehtod = method; return this; } public EventListener itemClick(String method){ this.itemClickMethod = method; return this; } public EventListener select(String method){ this.itemSelectMethod = method; return this; } public EventListener noSelect(String method){ this.nothingSelectedMethod = method; return this; } @Override public boolean onLongClick(View v) { return invokeLongClickMethod(handler,longClickMethod,v); } @Override public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) { return invokeItemLongClickMethod(handler,itemLongClickMehtod,arg0,arg1,arg2,arg3); } @Overridepublic void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,long arg3) { invokeItemSelectMethod(handler,itemSelectMethod,arg0,arg1,arg2,arg3); } @Override public void onNothingSelected(AdapterView<?> arg0) { invokeNoSelectMethod(handler,nothingSelectedMethod,arg0); } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { invokeItemClickMethod(handler,itemClickMethod,arg0,arg1,arg2,arg3); } @Override public void onClick(View v) { invokeClickMethod(handler, clickMethod, v); } /** * 点击事件处理方法(实际上这里是回调了使用注解的类的事件处理方法) * */ private static Object invokeClickMethod(Object handler, String methodName, Object... params){ if(handler == null) return null; //判断如何没有Activity传进来,则不做处理,直接返回 Method method = null; try{ method = handler.getClass().getDeclaredMethod(methodName,View.class);//获取指定事件处理方法名的Method对象, if(method!=null) return method.invoke(handler, params); //回调事件处理方法 else throw new ViewException("no such method:"+methodName);//这里抛出的是Afinal框架自己定义的一个异常, }catch(Exception e){ e.printStackTrace(); } return null; } /** * 长按事件处理方法(实际上这里是回调了使用注解的类的事件处理方法) * */ private static boolean invokeLongClickMethod(Object handler, String methodName, Object... params){ if(handler == null) return false; Method method = null; try{ //public boolean onLongClick(View v) method = handler.getClass().getDeclaredMethod(methodName,View.class); if(method!=null){ Object obj = method.invoke(handler, params); return obj==null?false:Boolean.valueOf(obj.toString()); } else throw new ViewException("no such method:"+methodName); }catch(Exception e){ e.printStackTrace(); } return false; } /** * 条目点击事件处理方法(实际上这里是回调了使用注解的类的事件处理方法) * */ private static Object invokeItemClickMethod(Object handler, String methodName, Object... params){ if(handler == null) return null; Method method = null; try{ ///onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class); if(method!=null) return method.invoke(handler, params); else throw new ViewException("no such method:"+methodName); }catch(Exception e){ e.printStackTrace(); } return null; } /** * 条目长按事件处理方法(实际上这里是回调了使用注解的类的事件处理方法) * */ private static boolean invokeItemLongClickMethod(Object handler, String methodName, Object... params){ if(handler == null) throw new ViewException("invokeItemLongClickMethod: handler is null :"); Method method = null; try{ ///onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class); if(method!=null){ Object obj = method.invoke(handler, params); return Boolean.valueOf(obj==null?false:Boolean.valueOf(obj.toString())); } else throw new ViewException("no such method:"+methodName); }catch(Exception e){ e.printStackTrace(); } return false; } /** * 条目选中事件处理方法(实际上这里是回调了使用注解的类的事件处理方法) * */ private static Object invokeItemSelectMethod(Object handler, String methodName, Object... params){ if(handler == null) return null; Method method = null; try{ ///onItemSelected(AdapterView<?> arg0, View arg1, int arg2,long arg3) method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class); if(method!=null) return method.invoke(handler, params); else throw new ViewException("no such method:"+methodName); }catch(Exception e){ e.printStackTrace(); } return null; } /** * 条目取消选中事件处理方法(实际上这里是回调了使用注解的类的事件处理方法) * */ private static Object invokeNoSelectMethod(Object handler, String methodName, Object... params){ if(handler == null) return null; Method method = null; try{ //onNothingSelected(AdapterView<?> arg0) method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class); if(method!=null) return method.invoke(handler, params); else throw new ViewException("no such method:"+methodName); }catch(Exception e){ e.printStackTrace(); } return null; } }
第四步:设计注解消费机,为Activity的View成员属性绑定View
public abstract class FinalActivity extends Activity { /** * 为Activity设置视图 * * @param layoutResID 布局文件的ID */ public void setContentView(int layoutResID) { super.setContentView(layoutResID); //调用注解消费机 initInjectedView(this); } /** * @param view View * @param params 布局属性 */ public void setContentView(View view, LayoutParams params) { super.setContentView(view, params);//调用注解消费机 initInjectedView(this); } /** * @param view View */ public void setContentView(View view) { super.setContentView(view);//调用注解消费机 initInjectedView(this); } /** *注解消费机重载方法 * * @param activity */ public static void initInjectedView(Activity activity) { //重载的方法,带两个参数,第一个参数是Activity类型的,第二个参数是Activity的根View //参数是Activity,说明只有在Activity中可以使用注解 initInjectedView(activity, activity.getWindow().getDecorView()); } /**注解消费机 * @param injectedSource 注入源 * @param sourceView 源View */ public static void initInjectedView(Object injectedSource, View sourceView) { //通过反射获得所有的属性 Field[] fields = injectedSource.getClass().getDeclaredFields(); //判断注入源是否有字段,如果有且个数大于0,则遍历所有的字段 if (fields != null && fields.length > 0) { for (Field field : fields) { try { //其字段可访问,突破Java封装的限制 field.setAccessible(true); //获得属性的值 ,如果不为null,则不处理这个属性值 if (field.get(injectedSource) != null) continue; //获得属性上的ViewInject注解, ViewInject viewInject = field.getAnnotation(ViewInject.class); if (viewInject != null) {//不为null说明这个属性上有这个注解 //获得注解的参数值,id int viewId = viewInject.id(); //通过findViewById()找到View,并赋值给该属性,这个属性的值就是找到的View field.set(injectedSource, sourceView.findViewById(viewId)); } } catch (Exception e) { e.printStackTrace(); } } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }}
第五步:完善注解消费机,为Activity的View成员属性注册事件监听器
public abstract class FinalActivity extends Activity { /** * 为Activity设置视图 * * @param layoutResID 布局文件的ID */ public void setContentView(int layoutResID) { super.setContentView(layoutResID); // initInjectedView(this); } /** * @param view View * @param params 布局属性 */ public void setContentView(View view, LayoutParams params) { super.setContentView(view, params); initInjectedView(this); } /** * @param view View */ public void setContentView(View view) { super.setContentView(view); initInjectedView(this); } /** * 注解消费机重载方法 * * @param activity */ public static void initInjectedView(Activity activity) { //重载的方法,带两个参数,第一个参数是Activity类型的,第二个参数是Activity的根View //参数是Activity,说明只有在Activity中可以使用注解 initInjectedView(activity, activity.getWindow().getDecorView()); } /**注解消费机 * @param injectedSource 注入源 * @param sourceView 源View */ public static void initInjectedView(Object injectedSource, View sourceView) { //通过反射获得所有的属性 Field[] fields = injectedSource.getClass().getDeclaredFields(); //判断注入源是否有字段,如果有且个数大于0,则遍历所有的字段 if (fields != null && fields.length > 0) { for (Field field : fields) { try { //其字段可访问,突破Java封装的限制 field.setAccessible(true); //获得属性的值 ,如果不为null,则不处理这个属性值 if (field.get(injectedSource) != null) continue; //获得属性上的ViewInject注解, ViewInject viewInject = field.getAnnotation(ViewInject.class); if (viewInject != null) {//不为null说明这个属性上有这个注解 //获得注解的参数值,id int viewId = viewInject.id(); //通过findViewById()找到View,并赋值给该属性,这个属性的值就是找到的View field.set(injectedSource, sourceView.findViewById(viewId)); //为属性绑定事件监听器,这里应该是只支持四种事件监听 setListener(injectedSource, field, viewInject.click(), Method.Click); setListener(injectedSource, field, viewInject.longClick(), Method.LongClick); setListener(injectedSource, field, viewInject.itemClick(), Method.ItemClick); setListener(injectedSource, field, viewInject.itemLongClick(), Method.itemLongClick); Select select = viewInject.select(); if (!TextUtils.isEmpty(select.selected())) { setViewSelectListener(injectedSource, field, select.selected(), select.noSelected()); } } } catch (Exception e) { e.printStackTrace(); } } } } private static void setViewSelectListener(Object injectedSource, Field field, String select, String noSelect) throws Exception { //获得属性字段的值 Object obj = field.get(injectedSource); //判断属性字段的值类型是否是View类型的 if (obj instanceof View) { //强制类型转化为AbsLIstView类型,调用setOnItemSelectedListener方法为View注册条目选中事件监听器 //new EventListener(injectedSource).select(select).noSelect(noSelect)这句代码的作用是什么? ((AbsListView) obj).setOnItemSelectedListener(new EventListener(injectedSource).select(select).noSelect(noSelect)); } } /** * @param injectedSource 注入源 * @param field 字段 * @param methodName 事件监听器方法名 * @param method 方法标识 * @throws Exception */ private static void setListener(Object injectedSource, Field field, String methodName, Method method) throws Exception { if (methodName == null || methodName.trim().length() == 0) return; //获取属性值 Object obj = field.get(injectedSource); //由method确定要处理的事件类型 switch (method) { case Click: if (obj instanceof View) { //为其注册事件监听器,new EventListener(injectedSource)创建事件监听器并初始化注入源 ((View) obj).setOnClickListener(new EventListener(injectedSource).click(methodName)); } break; case ItemClick: if (obj instanceof AbsListView) { ((AbsListView) obj).setOnItemClickListener(new EventListener(injectedSource).itemClick(methodName)); } break; case LongClick: if (obj instanceof View) { ((View) obj).setOnLongClickListener(new EventListener(injectedSource).longClick(methodName)); } break; case itemLongClick: if (obj instanceof AbsListView) { ((AbsListView) obj).setOnItemLongClickListener(new EventListener(injectedSource).itemLongClick(methodName)); } break; default: break; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } /** * 代表不同事件的枚举类 */ public enum Method { Click, LongClick, ItemClick, itemLongClick }}
设计思路搞清楚后,然后此框架就变的太容易了,下面是使用此模块的案例:
效果图:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" > <LinearLayout android:id="@+id/ll_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <EditText android:id = "@+id/et_username" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入用户名" /> <EditText android:id = "@+id/et_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入密码" /> </LinearLayout> <Button android:id = "@+id/btn_login" android:layout_below="@id/ll_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="登录" /></RelativeLayout>
逻辑代码:
public class MainActivity extends FinalActivity { public static final string TAG = "MainActivity"; @ViewInject(id = R.id.et_username) private EditText mUserNameEt; @ViewInject(id = R.id.et_password) private EditText mPassWordEt; @ViewInject(id = R.id.btn_login,click = "login") private Button mLoginBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /** * 处理登录事件的逻辑的方法 * @param view */ public void login(View view){ Log.i(TAG,"登录成功!"); }}
到此Afinal框架的FinalActivity模块就分析完了,下一篇将分析FinalDb模块。
- Android快速开发框架之Afinal设计思路分析(一)
- Android快速开发框架-------afinal
- Afinal Android快速开发框架
- Android--快速开发框架 afinal
- afinal logo Android的快速开发框架 afinal
- afinal logo Android的快速开发框架 afinal
- Android的快速开发框架afinal
- Android快速开发框架Afinal 迁移github
- Android的快速开发框架 afinal
- Afinal 0.3 发布,Android快速开发框架
- Android的快速开发框架 afinal
- Android的快速开发框架 afinal
- Android的快速开发框架 afinal
- Android的快速开发框架 afinal
- Android的快速开发框架 afinal
- Afinal 0.5 发布,Android快速开发框架
- Android的快速开发框架 afinal
- Android的快速开发框架 afinal
- 1085. Perfect Sequence (25)
- Visual Studio 2013光标变成方块
- hdoj 5248 序列变换 【贪心 + 二分】
- sublime 编译java
- 如何查看电脑最大支持多大内存
- Android快速开发框架之Afinal设计思路分析(一)
- 今天的面试题,我回来鞭尸了!
- 1086. Tree Traversals Again (25)
- BZOJ3329 Xorequ(数位DP)
- 别打扰做私事的时间
- atitit.ntfs ext 文件系统新特性对比
- 解决超卖思路
- 【Sublime Text 3/2】基本配置 与 插件
- 《Android源码设计模式》读书笔记 (7) 第7章 策略模式