Android快速开发框架之Afinal设计思路分析(一)

本文深入分析Android快速开发框架Afinal的设计思路,重点介绍FinalActivity、FinalDb、FinalBitmap和FinalHttp四个模块。FinalActivity利用注解简化View绑定和事件监听;FinalDb实现ORM,简化SQLite操作;FinalBitmap优化Bitmap加载,避免OOM;FinalHttp封装HttpClient,支持Ajax请求。文章还提及使用Afinal所需的网络和SDCard权限,以及模块实现的关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 {
@Override
protected 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);
   }
   
  @Override
public 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模块。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值