上篇文章對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;
}
}
重構完畢。