目錄.png
前言
新聞用戶端開發中,經常看到資料流中有很多視圖類型,類型有:新聞、圖檔、網頁連結、視訊、視訊+文字、廣告等等,這種情況下處理不好,則會導緻代碼臃腫,App 記憶體占用過高,清單卡頓。是以非常有必要對複雜 listView 進行一下優化。
MVP 模式使項目的整體結構更加清晰了,業務層、UI層、邏輯層進行了清晰的劃分,那麼實際項目中使用 MVP 模式後,最後有個疑問對于負責的 adapter 中該怎麼運用 MVP 模式進行重寫呢?
一、沒有運用 MVP 實作複雜 ListView 擴充卡
以下代碼是沒有優化前的處理,功能簡單,不加描述了,直接上代碼。
注意添加新布局後,别忘記修改
TYPE_COUNT
,否則引起數組越界異常。
class CustomAdapter extends BaseAdapter {
static final int TYPE_DATA = 0;
static final int TYPE_IMAGE = 1;
static final int TYPE_COUNT = 2;
@Override
public int getCount() {
return null == mArrayList ? 0 : mArrayList.size();
}
@Override
public int getViewTypeCount() {
return TYPE_COUNT;
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_IMAGE;
} else {
return TYPE_DATA;
}
}
@Override
public Object getItem(int position) {
return mArrayList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 1.初始化不同類型布局的控件
final ViewHolder viewHolder;
int type = getItemViewType(position);
if (convertView == null || convertView.getTag() == null) {
viewHolder = new ViewHolder();
switch (type) {
case TYPE_DATA:
convertView = View.inflate(mContext, R.layout.item_text, null);
viewHolder.tv_text = (TextView) convertView.findViewById(R.id.tv_text);
break;
case TYPE_IMAGE:
convertView = View.inflate(mContext, R.layout.item_image, null);
break;
}
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
// 2.渲染不同布局類型的資料
if (type == TYPE_DATA) {
renderData(viewHolder, position);
}
if (type == TYPE_IMAGE) {
}
return convertView;
}
}
// 抽取渲染不同類型資料的方法。防止getView()方法體過于複雜
private void renderData(ViewHolder viewHolder, int position) {
String title = mArrayList.get(position);
viewHolder.tv_text.setText(title);
}
// 所有類型的布局的控件都包含在内
static class ViewHolder {
public TextView tv_text;
public ImageView poster;
}
本代碼實作方式參考廣告聯盟demo
二、使用 MVP 後高效渲染複雜 listView
每個 item 的資料處理是在單獨一個 ViewHolder 上處理。
所有的 ViewHolder 所在包結構
view >>> viewholder
下面。
public class NewsListAdapter extends BaseAdapter {
private static final int TYPE_ONE = 0;
private static final int TYPE_TWO = 1;
private static final int TYPE_THR = 2;
private static final int TYPE_COUNT = 3;
private List<NewEntity> newsList;
...
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
// 1.擷取 item 對應的那組元素
NewEntity entity = newsList.get(position);
// 2. 建立各個 XXHolder 引用,假設有3個視圖分别對應了3個Holder
OneHolder oneHolder;
TwoHolder twoHolder;
ThrHolder thrHolder;
// 3.
int type = getItemViewType(position);
switch(type) {
case TYPE_ONE:
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.item_one, null);
oneHolder = new OneHolder(convertView);
convertView.setTag(oneHolder);
} else {
oneHolder = (OneHolder) convertView.getTag();
}
oneHolder.bindData(position, entity);
break;
case TYPE_TWO:
...
break;
}
return convertView;
}
}
每個 item 的資料處理是在單獨一個 ViewHolder 上處理,ViewHolder 中的處理如下:
- 做 findViewById 和資料渲染的處理
public class OneHolder {
TextView tv_01;
TextView tv_02;
// 擷取到每個Item View的引用
/**
* 可傳入參數:convertView / datas
**/
//public OneHolder(View convertView) {
public OneHolder(View convertView, List<T> datas) {
this.mDatas = datas;
if (convertView != null) {
// 這裡做 findViewById操作
tv_01 = (TextView)convertView.findViewById(R.id.tv_01);
}
}
/**
* 要顯示的資料對象
* 可傳入參數:position
**/
public void bindData(int position, NewEntity entity) {
String title = entity.getTitle();
tv_01.setText(String.valueOf(title));
}
}
有時候 ViewHolder 中想要操作 Adapter 中的 datas 這時候,可以在構造函數上加個參數
// 擷取到每個Item View的引用
public OneHolder(View convertView, List<Object> list) {
if (convertView != null) {
// 這裡做 findViewById操作
tv_01 = (TextView)convertView.findViewById(R.id.tv_01);
}
}
BaseHolder 簡單抽取
public abstract class BaseHolder<T> {
public List<T> mDatas;
public void bindData(List<T> datas) {
this.mDatas = datas;
}
public BaseHolder(int position);
}