編寫適配器代碼時經常被如下幾個問題所困擾:
1.業務層和適配器中對同一組數據進行維護,難以管理
2.在業務層針對數據進行修改後必須通知適配器更新,不然提示
The content of the adapter has changed but ListView did not receive anotification
3.業務層修改數據時充斥大量的非空&數據標準化等冗餘代碼
針對前兩個問題,能夠將數據交由適配器去管理,業務層對數據的增刪改查均經過適配器進行處理,這樣僅須要維護好adapter中的數據便可。
關於數據的非空判斷以及增刪改查等操做,能夠抽取數據操做類來簡化適配器當中的邏輯。
下面給出具體的代碼實現
適配器更新方式接口定義,其具體實現可根據適配器類型(BaseAdapter/PageAdapter/RecyclerView.Adapter)自行調整。
/**
* @Description:
* @author: Xiaoxuan948
* @date: 2016/7/20 20:39
*/
public interface INotifyAdapterDataSetChange {
/**
* 通知適配器更新
*/
void notifyUnityAdapterDataChange();
void notifyUnityAdapterDataInsert(int position);
void notifyUnityAdapterDataUpdate(int position);
void notifyUnityAdapterDataRemove(int position);
}
接口IAdapterDataModifyHelper定義針對數據的各類操做,其子類AbsDataModifyHelper進行簡要實現。
public abstract class AbsDataModifyHelper<T> implements IAdapterDataModifyHelper<T> {
private final UtilsLog lg = UtilsLog.getLogger(AbsDataModifyHelper.class);
protected List<T> mDataResources;
protected INotifyAdapterDataSetChange INotifyDataSetChange;
public AbsDataModifyHelper() {
this.mDataResources = new ArrayList<>();
}
@Override
public final void setNotifyAdapterDataSetChange(INotifyAdapterDataSetChange INotifyDataSetChange) {
this.INotifyDataSetChange = INotifyDataSetChange;
}
@Override
public final List<T> getDataResources() {
return mDataResources;
}
//省略部分代碼
}
觀察可知,在
AbsDataModifyHelper
構造方法中實例化
mDataResources對象,其對應於列表控件中顯示的數據。
setNotifyAdapterDataSetChange爲外界提供數據更新的接口注入方法,在數據修改後調用INotifyDataSetChange的notify...()方法便可通知適配器更新。
開發人員可自行擴展AbsDataModifyHelper,下面給出一個示例實現類DataModifyHelper。
/**
* @Description:
* @author: Xiaoxuan948
* @date: 2016/8/26 10:04
*/
public class DataModifyHelper<T> extends AbsDataModifyHelper<T> {
private final UtilsLog lg = UtilsLog.getLogger(DataModifyHelper.class);
@Override
public void setDataResource(List<? extends T> setDataResources) {
/*針對集合空數據進行處理*/
if (UtilsCollections.isCollectionNotEmpty(setDataResources) && setDataResources.contains(null)) {
lg.e("setDataResource集合包含null數據");
setDataResources = Lists.newArrayList(Collections2.filter(setDataResources, new Predicate<T>() {
@Override
public boolean apply(T input) {
return input != null;
}
}));
}
if (!UtilsCollections.isCollectionNotEmpty(setDataResources)) {
return;
}
/*針對類型不匹配進行處理*/
this.mDataResources = Lists.transform(setDataResources, new Function<Object, T>() {
@Override
public T apply(Object input) {
return (T) input;
}
});
INotifyDataSetChange.notifyUnityAdapterDataChange();
}
@Override
public void addDataResource(int location, List<? extends T> addDataResources) {
if (UtilsCollections.isCollectionNotEmpty(addDataResources) && addDataResources.contains(null)) {
lg.e("addDataResource集合包含null數據");
addDataResources = Lists.newArrayList(Collections2.filter(addDataResources, new Predicate<T>() {
@Override
public boolean apply(T input) {
return input != null;
}
}));
}
if (!UtilsCollections.isCollectionNotEmpty(addDataResources)) {
lg.e("addDataResource:待加入的集合爲空");
return;
}
location = proofOperateDataLocation(location);
this.mDataResources.addAll(location, addDataResources);
INotifyDataSetChange.notifyUnityAdapterDataInsert(location);
}
@Override
public void reviseDataResource(int position, T enity) {
if (isOperateLocationRight(position)) {
this.mDataResources.set(position, enity);
INotifyDataSetChange.notifyUnityAdapterDataUpdate(position);
} else {
lg.e("reviseDataResource failed because position out of size " + this.mDataResources.size());
}
}
@Override
public void removeDataResourceOnPosition(int position) {
this.mDataResources.remove(position);
INotifyDataSetChange.notifyUnityAdapterDataRemove(position);
}
@Override
public void clear() {
this.mDataResources.clear();
INotifyDataSetChange.notifyUnityAdapterDataChange();
}
}
setDataResource方法中,針對List數據先進行非空過濾,再判斷List非空後進行數據修改,以確保
mDataResources集合始終非空。這裏會注意到其參數使用無限制通配符,主要是爲了提升程序的擴展性,當適配器基於接口編程時能方便set數據。(使用
transform的緣由
:
List<Child>
沒法轉爲
List<Parent>)
addDataResource的實現過程同setDataResource基本一致,都是針對數據集進行非空過濾以及判斷等一系列處理。
使用示例(博客園可經過左邊"搜索"進入):