Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android之ListView分組及字母索引導航(2)重構-接口

android之ListView分組及字母索引導航(2)重構-接口

編輯:關於Android編程

上篇文章對listView 分組和字母索引導航的實現思路做了分析,並依照思路一步步實現,到最後已經較好的實現了全部功能。但是仔細研究就會發現其實現不夠好,主要問題:

1. 對於一個使用范圍比較廣泛的布局,以上實現不夠通用,尤其是Bo中需加上一些多余的字段,這些字字段本身並沒有意義。

2. 代碼都糅合在activity中。

針對以上兩點做一些代碼重構。首先我們把其優化為一個通用的activity.這樣做成通用的View就很容易;然後對代碼進行抽取和重構。

想法和思路

以往代碼的一個主要問題就是“污染”原有的Bo,而污染的主要原因是需要用這些附加的字段來進行數據處理和生成列表分組標簽的時候使用。

原有代碼如下:

public class TestBo {
 
    /**
     * 主要字段
     */
    private String boStr = null;
   
   
    /**
     * bo拼音緩存
     */
    private String boPinYin = null;
    /**
     * Bo標簽標記
     */
    private String boTagFlag = null;
   
   
    public TestBo() {
       super();
    }
 
    public TestBo(String str) {
       super();
       this.boStr = str;
    }
   
   
    public String getBoStr() {
       return boStr;
    }
 
    public void setBoStr(String boStr) {
       this.boStr = boStr;
    }
 
    public String getSortStrPinyin() {
       return boPinYin;
    }
 
    public void setSortStrPinYin(String pinyin) {
       this.boPinYin = pinyin;
    }
 
    public void setTag(String tag) {
       this.boTagFlag = tag;
    }
    public String getTag() {
       return boTagFlag;
    }
}


其實以上Bo中真正有用的有主要字段,其他均為附加字段,其實生成列表只要要求Bo提供按照哪個字段分組就行了。

自然而然的我們就想到了接口,只要實現了相應的接口,接口方法返回需要“分組排序的值”。

數據處理做相應改變即可。

重構BO-接口

首先抽出以下接口:

public interface BoSort  {
 
    /**   
    * @date 2014-9-3
    * @Description: 獲取索引的字符串
    * @param  
    * @return String
    */
    public String getSortStr();
    /**  
    * @date 2014-9-3
    * @Description: 獲取索引字符串的拼音,這個最好可以有緩存
    * @param  
    * @return String
    */
    public String getSortStrPinyin();
   
    /**  
    * @date 2014-9-3
    * @Description:
    * @param  
    * @return void
    */
    public void setSortStrPinYin(String pinyin);
    /**  
    * @date 2014-9-3
    * @Description: 設置標簽,需要緩存
    * @param  
    * @return void
    */
    public void setTag(String tag);
    /**  
    * @date 2014-9-3
    * @Description: 獲取標簽,如果為null,說明不是標簽
    * @param  
    * @return String
    */
    public String getTag();
}


相應Bo實現以上接口即可。但是我們可以提供一個默認實現,這還是一個抽象類,Bo只要繼承這個默認實現,並實現為實現的方法public String getSortStr();

/**  
 * @date 2014-9-3
 * @Description: 只需實現 getSortStr 其他不要修改
   
 */
public  abstract class DefaultBoSortImp implements BoSort{
 
   
    /**
     * bo拼音緩存
     */
    private String boPinYin = null;
    /**
     * Bo標簽標記
     */
    private String boTagFlag = null;
   
    /**
     * 一定要有這個構造函數
     */
    public DefaultBoSortImp() {
       super();
    }
 
    @Override
    public String getSortStrPinyin() {
       return boPinYin;
    }
 
    @Override
    public void setSortStrPinYin(String pinyin) {
       this.boPinYin = pinyin;
    }
 
    @Override
    public void setTag(String tag) {
       this.boTagFlag = tag;
    }
    @Override
    public String getTag() {
       return boTagFlag;
    }
}

數據處理

整體的實現過程和以前類似,數據處理的時候稍微有些改變。我們把數據處理單獨抽為一個類,可見處理的過程中,生成分組標簽的時候,采用反射,且此數據處理只依賴與接口,而不是具體的Bo,降低了耦合。

public class RulerUtil {
 
   
    /**
     * 列表適配??
     */
    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
     * @return返回處理後的數據
     * @Description:處理數據,排序,添加標簽
     */
    public  static ArrayList genSortedDataAndTagLocation(List myData, HashMap tagLocation) throws InstantiationException, IllegalAccessException {
      
      
       ArrayList res = new ArrayList();
       res.addAll(myData);
       //首先排序
       Collections.sort(res, new Comparator() {
           @Override
           public int compare(BoSort lhs, BoSort 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++) {
           BoSort temp = res.get(i);
           char tempTag = checkAndGetPinyin(temp);
           if(Arrays.binarySearch(letters, tempTag) < 0){
              tempTag = '#';
           }
           if (nowTag != tempTag) {
              //反射生成標簽
              Class boClass = temp.getClass();
              BoSort tagBO = boClass.newInstance();
              tagBO.setTag(tempTag+"");
              res.add(i, tagBO);
              tagLocation.put(tempTag + "", i);
              i++;
              size++;
              nowTag = tempTag;
           }
       }
       tagLocation.put("#", 0);
       return res;
    }
   
    private static 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';
    }
}

Adaptor實現

Adptor的實現和之前一樣,只是adaptor也是只依賴於接口,不依賴於具體的Bo。

Activity的重構

構造一個通用的抽象activity。當需要分組導航的話,只需要繼承之,並實現其中的返回數據的方法即可。

首先把右邊的字母索引抽出來,做成一個View.

1. RulerWidget

單獨的View,可以直接在xml布局中使用。


/**  
 * @Description: 右邊尺子導航,需要調用  setOnRulerTouch方法設置回調接口
 */
public class RulerWidget extends LinearLayout{
   
    private static final int INDEX_LENGTH = RulerUtil.indexStr.length;
 
 
    public RulerWidget(Context context) {
       super(context);
       init();
    }
   
   
    public RulerWidget(Context context, AttributeSet attrs) {
       super(context, attrs);
       init();
    }
    public RulerWidget(Context context, AttributeSet attrs, int defStyle) {
       super(context, attrs, defStyle);
       init();
    }
   
    private void init(){
       int color = getResources().getColor(R.color.g_ruler_letter_color);
       LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
       params.gravity = Gravity.CENTER_HORIZONTAL;
       this.bringToFront();
 
       params.weight = 1;
       for (int i = 0; i < RulerUtil.indexStr.length; i++) {
           final TextView tv = new TextView(getContext());
           tv.setLayoutParams(params);
           tv.setTextColor(color);
           tv.setGravity(Gravity.CENTER);
           tv.setText(RulerUtil.indexStr[i]);       
           this.addView(tv);
       }
       this.setOnTouchListener(new OnTouchListener() {
 
           @Override
           public boolean onTouch(View v, MotionEvent event) {
              int height = v.getHeight();
              float pos = event.getY();
              int sectionPosition = (int) ((pos / height) / (1f /INDEX_LENGTH));
              if (sectionPosition < 0) {
                  sectionPosition = 0;
              } else if (sectionPosition > INDEX_LENGTH-1) {
                  sectionPosition = INDEX_LENGTH-1;
              }
 
              switch (event.getAction()) {
              case MotionEvent.ACTION_DOWN:
                  if (onRulerTouch!=null) {
                     onRulerTouch.onDown(sectionPosition);
                  }
                  RulerWidget.this.setBackgroundResource(R.color.g_ruler_selected);
                  break;
              case MotionEvent.ACTION_MOVE:
                  if (onRulerTouch!=null) {
                     onRulerTouch.onMove(sectionPosition);
                  }
                  break;
              default:
                  if (onRulerTouch!=null) {
                     onRulerTouch.onOthers();
                  }
                  RulerWidget.this.setBackgroundResource(R.color.g_blank);
              }
              return true;
           }
       });
    }
    /**
     * 回調
     */
    private OnRulerTouch onRulerTouch;
   
   
    public void setOnRulerTouch(OnRulerTouch onRulerTouch) {
       this.onRulerTouch = onRulerTouch;
    }
 
 
}
/**  
 * @date 2014-9-3
 * @Description: ruler觸摸回調
 */
public interface OnRulerTouch{
    public void onDown(int position);
    public void onMove(int position);
    public void onUP();
    public void onOthers();
}

2. Activity

一個抽象的activity. 布局和以前類似。不在貼。

/**  
 * @date 2014-9-3
 * @Description:需要實現這個獲取數據的方法 
 *    public abstract List getDataList();
 */
public abstract class RulerActivity extends Activity{
 
    protected TextView noDataView;
   
    protected TextView RulerTag;
    protected ProgressBarWithText progress;
   
    protected ListView listView;
   
    protected RulerWidget ruler;
   
   
    private RulerAdapter rulerAdapter;
    private List originalList;
    private List dealedList;
    private HashMap tagLocation = new HashMap();
   
    /**  
    *   
    */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.g_ruler);
       findView();
       initView();
       initData();
    }
 
   
 
    private void findView() {
       noDataView = (TextView) findViewById(R.id.g_base_list_nodata);
       RulerTag = (TextView) findViewById(R.id.g_ruler_tag);
       progress = (ProgressBarWithText) findViewById(R.id.g_base_progressbar_withtext);
       listView = (ListView) findViewById(R.id.g_base_list);
       ruler = (RulerWidget) findViewById(R.id.g_ruler);
    }
    private void initView() {
       progress.setVisibility(View.VISIBLE);
       RulerTag.setVisibility(View.GONE);
       noDataView.setVisibility(View.GONE);
       listView.setVisibility(View.GONE);
       ruler.setVisibility(View.GONE);
    }
    private void initData() {
       new GetDataAsyTask().execute();
    }
   
   
    /**  
    * @date 2014-9-4
    * @Description: 需要實現這個獲取數據的方法
    * @param  
    * @return List
    */
    public abstract List getDataList();
   
   
    /**  
    * @date 2014-9-3
    * @Description:
    * @param  
    * @return void
    */
    private void handleSuccessData() {
       listView.setVisibility(View.VISIBLE);
       ruler.setVisibility(View.VISIBLE);
       rulerAdapter = new RulerAdapter(dealedList, this);
       ruler.setOnRulerTouch(new OnRulerTouch() {
           @Override
           public void onUP() {
           }
           @Override
           public void onOthers() {
              RulerTag.setVisibility(View.GONE);
           }
           @Override
           public void onMove(int position) {
              RulerTag.setText(RulerUtil.indexStr[position]);
              listView.setSelection(getPosition(position));
           }
           @Override
           public void onDown(int position) {
              RulerTag.setVisibility(View.VISIBLE);
              RulerTag.setText(RulerUtil.indexStr[position]);
              listView.setSelection(getPosition(position));
           }
       });
      
       listView.setAdapter(rulerAdapter);
       rulerAdapter.notifyDataSetChanged();
      
    }
   
    /**
     * @Description: 獲取觸摸字母導航的時候,列表要滾動到的位置。如果觸摸的字母,在標簽tagLocation 映射中,不存,則向前尋找。
     */
    private Integer getPosition(final int j) {
       Integer pos = null;
       int i = j;
       while (pos == null && i <= RulerUtil.indexStr.length - 1) {
           pos = tagLocation.get(RulerUtil.indexStr[i]);
           i++;
       }
       if (pos == null) {
           pos = dealedList.size() - 1;
       }
       return pos;
    }
    class GetDataAsyTask extends AsyncTask {
 
      
      
      
       @Override
       protected void onPreExecute() {
           super.onPreExecute();
           progress.setVisibility(View.VISIBLE);
       }
   
       @Override
       protected Void doInBackground(Void... params) {
           originalList = getDataList();
           try {
              dealedList = RulerUtil.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();
       }
    }
   
}

至此重構完成。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved