上篇文章对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; } }
重构完毕。