android列表分组及字母导航-重构(2)-注解

上篇文章对listView 分组和字母索引导航进行了重构,重构之后,使新的实现只依赖于接口,而不是具体的Bo.但是还是要求原始的数据Bo实现接口或者继承抽象类。能不能把这一步也简化呢,只需要原始的数据Bolist? 答案是可以的,可以使用注解,也就是annnotion。

想法和思路

Java注解又叫java标注,java提供了一套机制,使得我们可以对方法、类、参数、包、域以及变量等添加标准(即附上某些信息)。且在以后某个时段通过反射将标注的信息提取出来以供使用。

分组listView 在上次重构后,最需要的信息就是“使用哪个字段进行分组导航”,故我们只要使用注解把这个信息标志出来即可。

另外还需要保存一些拼音等的缓存,那么可以把原始的Bo包装一下,利用泛型。下面一步步的来。

注解和Bo包装

注解只要标记按照bo的哪个字段分组排序即可,且注解信息保留在运行时:

@Target(ElementType.TYPE)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface RulerSortStr   {
    String sortField();
}

对Bo利用泛型对Bo进行包装,包装类实现之前的接口BoSort或者继承抽象类DefaultBoSortImp,实现方法getSortStr时利用Bo的注解信息。

public class RulerListDataWrapper<T> extends DefaultBoSortImp{

    private T data;

    public RulerListDataWrapper() {
       super();
    }

    public RulerListDataWrapper(T data) {
       super();
       this.data = data;
    }

    public T getData() {
       return data;
    }

    public void setData(T data) {
       this.data = data;
    }

/**
    *    利用 T的注解信息实现此方法
    */
    @Override
    public String getSortStr() {
       Class<?> temp = data.getClass();
       RulerSortStr anno = temp.getAnnotation(RulerSortStr.class);
       if (anno==null) {
           return "";
       }
       String sortField = anno.sortField();
       Field f;
       try {
           f = temp.getDeclaredField(sortField);
           f.setAccessible(true);
           return (String) f.get(data);
       } catch (Exception e) {
           e.printStackTrace();
           return "";
       }
    }

}

RulerUtil重构

此工具类也重构为泛型,此类把原始数据bo列表List<T>构造为包装器类型List<RulerListDataWrapper<T>>。添加的标签也是包装器类型(RulerListDataWrapper<T>),泛型化之后,不再依赖具体的Bo.

public class RulerUtil<T> {

    /**
     * 列表适配??
     */
    public static final String[] indexStr = { "#", "A", "B", "C", "D", "E", "F", "G", "H",
            "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
            "V", "W", "X", "Y", "Z" };
    public static final char[] letters = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
            'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
            'V', 'W', 'X', 'Y', 'Z' };

    /**
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @date 2014-7-28
     * @return返回处理后的数据
     * @Description:处理数据,排序,添加标签
     */
    public   List<RulerListDataWrapper<T>> genSortedDataAndTagLocation(List<T> myData, HashMap<String, Integer> tagLocation) throws InstantiationException, IllegalAccessException {

       List<RulerListDataWrapper<T>> res = getList(myData);
       //首先排序
       Collections.sort(res, new Comparator<RulerListDataWrapper<T>>() {
           @Override
           public int compare(RulerListDataWrapper<T> lhs, RulerListDataWrapper<T> rhs) {
              char firChar = checkAndGetPinyin(lhs);
              char secChar = checkAndGetPinyin(rhs);
              if (firChar < secChar) {
                  return -1;
              } else if (firChar > secChar) {
                  return 1;
              } else
                  return 0;
           }
       });

       int size = res.size();
       int i = 0;
       char nowTag = '\0';

       for (i = 0; i < size; i++) {
           RulerListDataWrapper<T> temp = res.get(i);
           char tempTag = checkAndGetPinyin(temp);
           if(Arrays.binarySearch(letters, tempTag) < 0){
              tempTag = '#';
           }
           if (nowTag != tempTag) {
              RulerListDataWrapper<T> tagBO = new RulerListDataWrapper<T>();
              tagBO.setTag(tempTag+"");
              res.add(i, tagBO);
              tagLocation.put(tempTag + "", i);
              i++;
              size++;
              nowTag = tempTag;
           }
       }
       tagLocation.put("#", 0);
       return res;
    }

    private  char checkAndGetPinyin(BoSort bo){
       String pinyinStr = bo.getSortStrPinyin();
       if (pinyinStr==null) {
           bo.setSortStrPinYin(HanziToPinyin.getPinYin(bo.getSortStr()).toUpperCase());
           pinyinStr = bo.getSortStrPinyin();
       }
       if(pinyinStr!=null&&pinyinStr.length()>=1){
           return pinyinStr.charAt(0);
       }
       return '\0';
    }

    public  List<RulerListDataWrapper<T>> getList(List<T> data){
       List<RulerListDataWrapper<T>> res = new ArrayList<RulerListDataWrapper<T>>();
       for (T  t: data) {
           res.add(new RulerListDataWrapper<T>(t));
       }
       return res;
    }

Activity和Adaptor

也都进行泛型化。

1.adaptor

首先是adaptor,其所需要的数据是List<RulerListDataWrapper<T>>,泛型化之后,如下:

public class RulerAdapter<T> extends BaseAdapter{

    /**
     * 经过处理的数据
     */
    private List<RulerListDataWrapper<T>> list;

    /**
     * aa
     */
    private Context mContext;

    /**
     *
     */
    public RulerAdapter() {
       super();
       // TODO Auto-generated constructor stub
    }

    /**
     * @param list
     */
    public RulerAdapter(List<RulerListDataWrapper<T>> list) {
       super();
       this.list = list;
    }

    /**
     *
     */
    public RulerAdapter(List<RulerListDataWrapper<T>> list, Context mContext) {
       super();
       this.list = list;
       this.mContext = mContext;
    }
    public List<RulerListDataWrapper<T>> getList() {
       return list;
    }

    public void setList(List<RulerListDataWrapper<T>> list) {
       this.list = list;
    }

    public Context getmContext() {
       return mContext;
    }

    public void setmContext(Context mContext) {
       this.mContext = mContext;
    }

    @Override
    public int getCount() {
       return list.size();
    }

    @Override
    public RulerListDataWrapper<T> getItem(int arg0) {
       // TODO Auto-generated method stub
       return list.get(arg0);
    }

    @Override
    public long getItemId(int position) {
       return 0;
    }

    /**
    * @date 2014-9-3
    * @Description: 需要的时候覆盖此方法,提供自己的自定义非标签视图
    * @param
    * @return View
    */
    public View getContentView(int position,RulerListDataWrapper<T> bo){
       return null;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       ViewHolder holder;

       if (convertView == null) {
           convertView = LayoutInflater.from(mContext).inflate(R.layout.g_ruler_list_item, null);
           holder = new ViewHolder();
           holder.tag = (TextView) convertView.findViewById(R.id.g_ruler_list_item_tag);
           holder.content = (LinearLayout) convertView.findViewById(R.id.g_ruler_list_item);
           convertView.setTag(holder);
       } else {
           holder = (ViewHolder) convertView.getTag();
       }
// 依赖于RulerListDataWrapper<T>
       final RulerListDataWrapper<T> bo =  getItem(position);

       String tag = bo.getTag();
       if(tag!=null){//是标签
           holder.tag.setVisibility(View.VISIBLE);
           holder.content.setVisibility(View.GONE);

           holder.tag.setText(tag);
       }else{//是内容
           //首先取自定义视图,如果没的话就自定义一个TextView add 到content中
           holder.content.removeAllViews();
           holder.tag.setVisibility(View.GONE);
           holder.content.setVisibility(View.VISIBLE);
           View contentView  = getContentView(position, bo);
           if(contentView==null){
              TextView textV = new TextView(mContext);
              textV.setText(bo.getSortStr());
              textV.setTextColor(Color.BLACK);
              textV.setGravity(Gravity.CENTER_VERTICAL);
              textV.setTextSize(16);
              contentView = textV;
           }
           holder.content.addView(contentView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
       }

       return convertView;
    }

    static class ViewHolder{
       TextView tag;
       LinearLayout content;
    }

2.Activity

Activity也泛型化,主要是对RulerUtil的调用和 获取数据时泛型化,其基本代码如下:

public abstract class RulerActivity<T> extends Activity{

    protected TextView noDataView;

    protected TextView RulerTag;
    protected ProgressBarWithText progress;

    protected ListView listView;

    protected RulerWidget ruler;

    private RulerAdapter<T> rulerAdapter;
    private List<T> originalList;
    private List<RulerListDataWrapper<T>> dealedList;
    private HashMap<String, Integer> tagLocation = new HashMap<String, Integer>();

    /**
    *
    */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.g_ruler);
       findView();
       initView();
       initData();
    }

    private void findView() {
       . . .
    }
    private void initView() {
       . . .
    }
    private void initData() {
       new GetDataAsyTask().execute();
    }

    /**
    * @date 2014-9-4
    * @Description: 需要实现这个获取数据的方法
    * @param
    * @return List<? extends BoSort>
    */
    public abstract List<T> getDataList();

    /**
    * @date 2014-9-3
    * @Description:
    * @param
    * @return void
    */
    private void handleSuccessData() {
       . . .

    }

    /**
     * @Description: 获取触摸字母导航的时候,列表要滚动到的位置。如果触摸的字母,在标签tagLocation 映射中,不存,则向前寻找。
     */
    private Integer getPosition(final int j) {
       . . .
    }
    class GetDataAsyTask extends AsyncTask<Void, Void, Void> {

       @Override
       protected void onPreExecute() {
           super.onPreExecute();
           progress.setVisibility(View.VISIBLE);
       }

       @Override
       protected Void doInBackground(Void... params) {
           originalList = getDataList();
           try {
              dealedList = new RulerUtil<T>().genSortedDataAndTagLocation(originalList, tagLocation);
           } catch (Exception e) {
              e.printStackTrace();
              if (dealedList!=null) {
                  dealedList.clear();
                  dealedList = null;
              }

              if (originalList!=null) {
                  originalList.clear();
                  originalList = null;
              }
              if (tagLocation!=null) {
                  tagLocation.clear();
                  tagLocation = null;
              }
           }
           return null;
       }

       @Override
       protected void onPostExecute(Void result) {
           progress.setVisibility(View.GONE);
           super.onPostExecute(result);
           if(dealedList==null){
              noDataView.setVisibility(View.VISIBLE);
              return;
           }
           handleSuccessData();
       }
    }

}

测试使用

测试使用只要继承意思activity和对Bo使用注解即可:

如下:

1.   Bo

使用注解,@RulerSortStr(sortField="testtr"),表名使用分组索引的字段为testtr。

@RulerSortStr(sortField="testtr")
public class TestAnnotationBo {

    private String testtr;
    private String test2;

    /**
     *
     */
    public TestAnnotationBo() {
       super();
       // TODO Auto-generated constructor stub
    }

    public TestAnnotationBo(String testtr, String test2) {
       super();
       this.testtr = testtr;
       this.test2 = test2;
    }

    public String getTesttr() {
       return testtr;
    }

    public void setTesttr(String testtr) {
       this.testtr = testtr;
    }

    public String getTest2() {
       return test2;
    }

    public void setTest2(String test2) {
       this.test2 = test2;
    }

}

2.   activity

只需要继承以上activity和实现获取数据的方法接口

public class TestRulerAnnoActivity extends RulerActivity<TestAnnotationBo>{
    @Override
    public List<TestAnnotationBo> getDataList() {
       List<TestAnnotationBo> res = new ArrayList<TestAnnotationBo>();
       TestAnnotationBo a = new TestAnnotationBo("aa","sdds");
       TestAnnotationBo a1 = new TestAnnotationBo("阿姨","sdds");
       TestAnnotationBo b = new TestAnnotationBo("bb","sdds");
       TestAnnotationBo b1 = new TestAnnotationBo("爸爸","sdds");
       res.add(b1);
       res.add(a);
       res.add(a1);
       res.add(b);
       return res;
    }
}

重构完毕。

时间: 2024-08-30 03:45:52

android列表分组及字母导航-重构(2)-注解的相关文章

自定义控件之android列表分组及字母导航

有了以上两篇文章的重构,现在把ListView分组列表重构为自定义控件就会非常简单,只需要把初始化操作放在自定义控件的构造函数里面.重构后的自定义控件以上一篇的注解重构为基础. 基本结构 这里首先贴上一张上篇文章重构后的activity的代码结构,相关的方法实现在之前两篇文章中都有贴出. 再贴一张重构后的View的结构.可见两者的结构都及其相似.不同的是上边的activity中有抽象方法getDataList(),而下边的没有,但是多了一个ILoadRulerData<T> iLoadData

android之ListView分组及字母索引导航(2)重构-接口

上篇文章对listView 分组和字母索引导航的实现思路做了分析,并依照思路一步步实现,到最后已经较好的实现了全部功能.但是仔细研究就会发现其实现不够好,主要问题: 1.               对于一个使用范围比较广泛的布局,以上实现不够通用,尤其是Bo中需加上一些多余的字段,这些字字段本身并没有意义. 2.               代码都糅合在activity中. 针对以上两点做一些代码重构.首先我们把其优化为一个通用的activity.这样做成通用的View就很容易:然后对代码进行

论字母导航的重要性,我们来实现一个联系人字母导航列表吧!

论字母导航的重要性,我们来实现一个联系人字母导航列表吧! 说起这个字母导航,我相信大家都不陌生,不论是联系人列表还是城市列表,基本上都是需要字母导航,那我们就有必要来研究一下这个思路的探索了,毕竟这是一个非常常用的功能,如果现在把轮子造好,那以后也可以节省很多的时间,同时,我们把思路理清楚了,对我们以后的帮助也是很大的,那好,既然如此,我们就一起来探索一下吧! 我们首选新建一个项目--LettersNavigation OK,工程建立好之后我们来思考一下这个功能的一个实现逻辑 逻辑不是很难,那我

Android仿联系人列表分组悬浮列表,PinnedHeaderListView源码解析

github地址:https://github.com/JimiSmith/PinnedHeaderListView 关于实现类似联系人列表,组的头部总是悬浮在listview最顶部的效果,github上面有两个比较好的实现,分别是pinnedSectionListview和pinnedHeaderListView,之所以选择后者进行源码解析,是因为后者的源码比较简单,便于我们理解实现的精髓所在. 如果你想直接实现Android仿联系人列表分组悬浮列表, 自定义PinnedHeaderListV

ListView 字母导航排序

一.概述 ListView字母导航排序,网上已经有很多代码和博客了, 这篇博文也是照搬网上的.  之所以写到这里,不是为了说明什么,只是为了以后自己查阅方便.本来公司要求实现expandablelistview + 字母导航的, 这里先抄袭一下 ListView的 字母导航, 此处没有实现挤压效果. 二.代码 package com.example.sortlistview; import android.content.Context; import android.graphics.Canv

浅谈android中手机联系人字母索引表的实现

实际上字母索引表的效果,可以说在现在的众多APP中使用的非常流行,比如支付宝,微信中的联系人,还有购物,买票的APP中选择全国城市,切换城市的时候,这时候的城市也就是按照一个字母索引的顺序来显示,看起来是很方便的.其实这种字母索引表的效果最开始是出现在微信的联系人中.因为觉得这种效果功能在今后的项目中可以说是非常常见,可能会用的上,所以准备来波博客讲述一下实现的原理,一来方便以后自己复习,二来如果能够帮助一些android路上奋斗小伙伴也是蛮有意义的. 下面我们先来看下效果图, 看完效果图后我们

如何获取android手机联系人并按字母展示(三)

如果获取contact的头像信息并展示: 如何根据photoId来获取bitmap: public static Bitmap getContactPhoto(Context context, long photoId, BitmapFactory.Options options) { if (photoId < 0) { return null; } Cursor cursor = null; try { cursor = context.getContentResolver().query(

android 列表图片优化经历

先上个优化之后的fps图,丝滑流畅:具体实现请看最终优化后的app 背景:一个通讯录app(开源地址),每次登陆时,针对每个用户,如果头像图片不在本地,则生成一个异步下载任务(AsyncTask). tips:判断图片是否在本地,咱使用的方法: 根据该图片的url,比如 http://images0.cnblogs.com/blog2015/339868/201507/230955108345303.png 截取com之后的字符串,则本地的地址是:app的包名/files/blog2015/33

字母导航跳转react核心代码

componentDidMount() { this.move(); } skipToDep(e) { let dom = document.getElementById(e); // 获取要跳至的字母节点 if (e === '#') { this.props.scroller.scrollTo(0, 0); } else { this.props.scroller.scrollTo(0, -dom.offsetTop); } } move() { // 监听字母导航列表的touchmove事