ListView之AutoupdataAdapter(二)

1、前言:

         前一篇文章写了一个Listener监听的Adapter,但这个Adapter只能我一个用户,假如我们在两个ListView只需要同时更新数据该怎么办呢?当然你可以另外再用一个自定义的List 来处理,那有没有更好的方法呢?当然有,下面就看看怎么来实现这个功能。

2、参考:

        还是参考,让我们来看看listview是怎么来观察Adapter数据变化的吧!打开BaseAdapter源码,我们会发现第一个字段就是DataSetObservable;

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();
那DataSetObservable又是什么呢?看下面:

public class DataSetObservable extends Observable<DataSetObserver> {
    
    public void notifyChanged() {
        synchronized(mObservers) {
           avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
  
    public void notifyInvalidated() {
        synchronized (mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onInvalidated();
            }
        }
    }
}
它只有两个简单的方法,这两个方法也只是遍历调用了父类中的成员变量的泛型DatasetObserver的onChange()和onInvalidated()方法,再看父类Observable:
public abstract class Observable<T> {
    protected final ArrayList<T> mObservers = new ArrayList<T>();
    public void registerObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            if (mObservers.contains(observer)) {
                throw new IllegalStateException("Observer " + observer + " is already registered.");
            }
            mObservers.add(observer);
        }
    }

    public void unregisterObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            int index = mObservers.indexOf(observer);
            if (index == -1) {
                throw new IllegalStateException("Observer " + observer + " was not registered.");
            }
            mObservers.remove(index);
        }
    }

    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }
    }
}
Observable只有一个List,并且提供了注册方法,注册方法也只是简单的把传进来的T放进List中而已;

            我们知道BaseAdapter也有注册的方法,它是怎么注册的呢?让我们来看一下:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();
    
    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

        它只是简单调用了它的成员变量的两个方法。
        看到这里我们知道,BaseAdapter中通过mDatasetObserver这个成员变量拥有了一个被观察者的List,并用只要调用notifychange()或者notifyInvalidated()方法,就可以通知到每一个观察者,并调用观察者的onChange()或onInvalidated()方法;

          再看看ListView吧!

          ListView继承自AbsListView,AbsListView中有一个内部类:

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    }
这个内部类复写了父类的onChange()方法,父类的这个方法在AdapterView的内部类AdapterDataSetObserver中进行了实现:

 class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();
          
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            requestLayout();
        }

            让我们来看看我们经常用到的更新数据用的BaseAdapter的NotifyDatasetChange()方法:

  public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

       绕来绕去,终于明白了吧!

       说白了,就是ListView是一个观察者,Adapter是一个被观察者,当你调用Adapter的NotifyDatasetChange()方法时,就是调用了DatasetObsable的notifyDatasetChange()方法,就会通知到每一个Observer,调用observer的onChange()方法,而当你调用Listview的setAdapter时:它new了一个AdapterDataSetObserver,并把它注册到了Adaper中,所以,你一调用就更新界面了!

  @Override
    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;

        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);

            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

            int position;
            if (mStackFromBottom) {
                position = lookForSelectablePosition(mItemCount - 1, false);
            } else {
                position = lookForSelectablePosition(0, true);
            }
            setSelectedPositionInt(position);
            setNextSelectedPositionInt(position);

            if (mItemCount == 0) {
                // Nothing selected
                checkSelectionChanged();
            }
        } else {
            mAreAllItemsSelectable = true;
            checkFocus();
            // Nothing selected
            checkSelectionChanged();
        }

        requestLayout();
    }
       

         写了这么多,其实仔细想想,再仔细想想,只要把我们前面的Lister换成多个,当数据变化时每一个都通知到不就行了?

         所以说,编程就是个思想,只要你想的到,思维方式稍加变化就有新的概念,最看不惯很多人满口的概念,还有满口的英文,好像有多神秘一样,其实,这是西方人的思维方式,不是我们中国人的。

      好了,看看我们的Observer实现的多个客户端的Adapter吧!

public class ObserableList<E> extends ArrayList<E> {
	private static final long serialVersionUID = -9031831111939356165L;
	private ArrayList<DatasetChangeObserver> mObservers;
	
	public void registObserver(DatasetChangeObserver listener) {
		this.mObservers.add(listener);
	}

	private void datasetChange(){
		if(!mObservers.isEmpty()){
			for (DatasetChangeObserver observer : mObservers) {
				observer.onDatasetChange();
			}
		}
	}
	@Override
	public boolean add(E object) {
		if(super.add(object)){
			datasetChange();
		}
		return false;
	}

	@Override
	public void add(int index, E object) {
		super.add(index, object);
		datasetChange();
	}

	@Override
	public boolean addAll(Collection<? extends E> collection) {
		if(super.addAll(collection)){
			datasetChange();
			return true;
		};
		return false;
	}

	@Override
	public boolean addAll(int index, Collection<? extends E> collection) {
		if(super.addAll(index, collection)){
			datasetChange();
			return true;
		}
		return false;
	}

	@Override
	public E remove(int index) {
		E e =super.remove(index);
		datasetChange();
		return e;
	}

	@Override
	public boolean remove(Object object) {
		if(super.remove(object)){
			datasetChange();
		}
		return false;
	}

	@Override
	protected void removeRange(int fromIndex, int toIndex) {
		super.removeRange(fromIndex, toIndex);
		datasetChange();
	}

	@Override
	public void clear() {
		super.clear();
		datasetChange();
	}

	@Override
	public E set(int index, E object) {
		E e = super.set(index, object);
		datasetChange();
		return e;
	}

	public static interface DatasetChangeObserver {
		public void onDatasetChange();
	}
}
          如果你想更简单一些,还可以使用前面的ListenableList,这样写:

public class ObserableList2<E> extends ListenerList<E>{
	private static final long serialVersionUID = -6118271325340704497L;
	private ArrayList<DatasetChangeObserver> mObservers;

	public void registObserver(DatasetChangeObserver listener) {
		this.mObservers.add(listener);
	}
	public void unregistObserver(DatasetChangeObserver listener) {
		this.mObservers.remove(listener);
	}
	@Override
	public void dataSetChange() {
		if(!mObservers.isEmpty()){
			for (DatasetChangeObserver observer : mObservers) {
				observer.onDatasetChange();
			}
		}
	}
}

        这样写完了,测试,没有问题,但是还有一个问题需要引起 重视,我们在使用我们的AutoupdataAdapter时,传进的数据只能是我们已经定义好的类,那么通用性就会大大降低,我们是不是可以这样写呢?

        首先抽取一个接口:

public interface Notifyable{
	//public interface NotifyList<E> extends List<E>{
	
	public void unregistDatasetChangeListener(DatasetChangeListener listener);
	public void registDatasetChangeListener(DatasetChangeListener listener);
	public void datasetChange();
	
	public static interface DatasetChangeListener {
		public void onDatasetChange();
	}
}
这个接口中有一个DatasetChangeListener接口,然后让ListenableList接口实现这个接口:

        

         另:上篇中的ObserableListener改为Listenable,特此更正,方便理解!

       

public class ListenableList<E> extends ArrayList<E> implements Notifyable{
	private static final long serialVersionUID = -9031831111939356165L;
	private DatasetChangeListener mListener;
	
	@Override
	public void unregistDatasetChangeListener(DatasetChangeListener listener) {
		this.mListener = listener;
	}

	@Override
	public void registDatasetChangeListener(DatasetChangeListener listener) {
		this.mListener = null;
	}
	@Override
	public void datasetChange(){
		if(mListener != null){
			mListener.onDatasetChange();
		}
	}
	@Override
	public boolean add(E object) {
		if(super.add(object)){
			datasetChange();
			return true;
		}
		return false;
	}

	@Override
	public void add(int index, E object) {
		super.add(index, object);
		datasetChange();
	}

	@Override
	public boolean addAll(Collection<? extends E> collection) {
		if(super.addAll(collection)){
			datasetChange();
			return true;
		};
		return false;
	}

	@Override
	public boolean addAll(int index, Collection<? extends E> collection) {
		if(super.addAll(index, collection)){
			datasetChange();
			return true;
		}
		return false;
	}

	@Override
	public E remove(int index) {
		E e =super.remove(index);
		datasetChange();
		return e;
	}

	@Override
	public boolean remove(Object object) {
		if(super.remove(object)){
			datasetChange();
			return true;
		}
		return false;
	}

	@Override
	protected void removeRange(int fromIndex, int toIndex) {
		super.removeRange(fromIndex, toIndex);
		datasetChange();
	}

	@Override
	public void clear() {
		super.clear();
		datasetChange();
	}

	@Override
	public E set(int index, E object) {
		E e = super.set(index, object);
		datasetChange();
		return e;
	}
}
NotifyableList继承ListenableList:
 
public class NotifyableList<E> extends ListenableList<E>{
	private static final long serialVersionUID = -6118271325340704497L;
	private ArrayList<DatasetChangeListener> mListeners = new ArrayList<DatasetChangeListener>();

	@Override
	public void unregistDatasetChangeListener(DatasetChangeListener listener) {
		this.mListeners.remove(listener);
	}
	@Override
	public void registDatasetChangeListener(DatasetChangeListener listener) {
		this.mListeners.add(listener);
	}
	@Override
	public void datasetChange() {
		if(!mListeners.isEmpty()){
			for (DatasetChangeListener observer : mListeners) {
				observer.onDatasetChange();
			}
		}
	}
}
同时,在AutoDatasetAdapter中,传的数据参数类型改为List,并改一个注册方法:

public  class AutoUpdataAdapter<T> extends GeneralAdapter<T> implements DatasetChangeListener {
	public AutoUpdataAdapter(int itemlayoutid, List<T> listdatas,IItemViewHolder iviewholder) {
		super(itemlayoutid, listdatas,iviewholder);
	}
	public AutoUpdataAdapter(int itemlayoutid, List<T> listdatas,IItemViewHolder iviewholder,boolean autoupdata) {
		super(itemlayoutid, listdatas,iviewholder);
		setAutoupdata(autoupdata);
	}

	public void setAutoupdata(boolean autoupdata) {
		if(mListDatas instanceof Notifyable){
			if(autoupdata){
				((Notifyable) mListDatas).registDatasetChangeListener(this);
			}else{
				((Notifyable) mListDatas).unregistDatasetChangeListener(this);
			}
		}else{
			throw new RuntimeException("autoupdata  the List must be instandeof Notifyable<T>,else do not autoupdata");
		}
	}
	@Override
	public void onDatasetChange() {
		notifyDataSetChanged();
	}
}

         这样如果你传入的是一个普通的List,不是我们自定义的,或者不调用setAutoupdata(boolean)方法,它还是和普通的Adapter一样使用,传入的是NotifyableList类型,并调用了setAutoupdata(boolean)方法,就是我们的自动更新Adapter了!

         如果你充分理解了以上思维方式 ,当然还可以根据自己的需求加一些功能。
  写完了,但本篇中的代码我没有测试,如果测试有问题欢迎留言!

          本文源码下载:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@cement

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值