ListView之AutoUpdataAdapter(一)

来源:互联网 发布:vscode 编译提示 编辑:程序博客网 时间:2024/04/29 21:23

1、前言:

        前面一篇文章写了GeneralAdapter,这个Adapter可以省去很多重复的代码,甚至可以用匿名内部类来写。前文链接:http://blog.csdn.net/xinxincement/article/details/51165284.

   但是上面封装的类,只能说写法比以前简洁了,并没有什么新的功能。我们在实际当中经常有这样的需求,就是当数据变化时,ListView可以自动进行更新,这样的功能怎么样来实现呢?

2、参考:

       其实在ListView与Adapter这两个常用类中,我们知道,调用Adapter的notyfyDatasetChange()方法,Listview的界面就可以进行更新,它是怎么做到的呢?这里不得不说一下设计模式,这里用到的就是观察者模式,(或者监听模式也可以实现)。所谓观察者模式就是有一方是观察者,有一方是被观察者,观察者需在被观察者那里进行注册。我们最最常用的各种Listener实质上也是观察者模式的一种.下面我们先来看看Listener的实现方式(以View.view.onClickListener为例):

    (1) Listener:

        View.class源码5126至5131行,这段代码表明将我们传进去的inClickListener实例赋值给了View的OnClickListener这个成员变量;

public void setOnClickListener(@Nullable OnClickListener l) {        if (!isClickable()) {            setClickable(true);        }        getListenerInfo().mOnClickListener = l;    }

ListenerInfo getListenerInfo() {     if (mListenerInfo != null) {            return mListenerInfo;        }        mListenerInfo = new ListenerInfo();        return mListenerInfo;    }
        这里的getListenerInfo()返回的是ListenerInfo类的实例,而ListenerInfo是View类中的一个静态内部类,它有很多的成员变量,其中就包括mOnClickListener,而mListenerInfo又是View的一个成员变量 查看View.class源码我们发现,有两个方法调用了ListenerInfo.mOnClicklistener.onClick(this)这个方法,它们分别是:
public boolean callOnClick() {        ListenerInfo li = mListenerInfo;        if (li != null && li.mOnClickListener != null) {            li.mOnClickListener.onClick(this);            return true;        }        return false;    }
public boolean performClick() {        final boolean result;        final ListenerInfo li = mListenerInfo;        if (li != null && li.mOnClickListener != null) {            playSoundEffect(SoundEffectConstants.CLICK);            li.mOnClickListener.onClick(this);            result = true;        } else {            result = false;        }        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);        return result;    }

       callOnClick()方法是提供给在程序中调用的,在内部没有直接使用,那么preFromClick()方法在内部有三处地方进行了调用,一个人是onKeyup(), 一个是辅助功能方法,再一个就是我们熟悉的onTouchEvent()了。源码我就不贴了,再贴就像是View源码分析了。
        以上分析就是说明了一个问题,就是我们将一个Listener实例注册到了View类中,然后View类在适当的地方调用,这样就实现了我们的方法得以执行,这就是所谓的回调吧!
3、实现
        学习了这么多,目的只有一个,那就是依照它的写法实现我们的目的,让我们的AutoUpdataAdapter实现自动更新,那么思路是什么呢?
        第一步:我们也写一个接口(xxxListener);
        第二步:在我们的数据源中写一个注册的方法;
        第三步:当数据源变化时调用这个方法;
        请看下面的代码:
  •    定义一个接口:
public interface DatasetChangeListener {public void onDatasetChange();}
  •    自定义数据源:
  •    数据源变化时调用接口方法
public class ObserableList<E> extends ArrayList<E> {        private static final long serialVersionUID = -9031831111939356165L;private DatasetChangeListener mListener;public void setDataChangeListener(DatasetChangeListener listener) {this.mListener = listener;}private void dataSetChange(){if(mListener != null){mListener.onDatasetChange();}}@Overridepublic boolean add(E object) {if(super.add(object)){dataSetChange();}return false;}@Overridepublic void add(int index, E object) {super.add(index, object);dataSetChange();}@Overridepublic boolean addAll(Collection<? extends E> collection) {if(super.addAll(collection)){dataSetChange();return true;};return false;}@Overridepublic boolean addAll(int index, Collection<? extends E> collection) {if(super.addAll(index, collection)){dataSetChange();return true;}return false;}@Overridepublic E remove(int index) {E e =super.remove(index);dataSetChange();return e;}@Overridepublic boolean remove(Object object) {if(super.remove(object)){dataSetChange();}return false;}@Overrideprotected void removeRange(int fromIndex, int toIndex) {super.removeRange(fromIndex, toIndex);dataSetChange();}@Overridepublic void clear() {super.clear();dataSetChange();}@Overridepublic E set(int index, E object) {E e = super.set(index, object);dataSetChange();return e;}}
       在这里,自定义了一个方法,为这个数据源类的成员变量DatasetChangeListener进行赋值(当然你也可以在构造中传进去),同时,每一个引起数据变化的方法都进行了复写,(当然也可以用JDK动态代理进行实现,不过这样要考虑不需要回调接口的方法的问题)调用接口中的方法onDatasetChange(),那么这个方法执行的是哪里的代码呢?
       下面看AutoUpdataAdapter类:
public  class AutoUpdataAdapter<T> extends GeneralAdapter<T> implements DatasetChangeListener {public AutoUpdataAdapter(int itemlayoutid, ObserableList<T> listdatas,IItemViewHolder iviewholder) {super(itemlayoutid, listdatas,iviewholder);listdatas.setDataChangeListener(this);}@Overridepublic void onDatasetChange() {notifyDataSetChanged();}}


        对了,你没有看错,就是这么简单,因为我们复用了前面一篇文章中的GeneralAdapter,只要将数据换成我们自定义的ObserableList,实现DatasetChangeListener,并在构造中将自身注册到ObserableList中,就可以了!

        到这里,只是实现了回调,那么这个方法要怎么写呢?对了,notifyDatasetChange();
其实这个方法本身的实现是一个观察者模式,具体实现看下面Oberser的分析。
        最后,写一个Activity测试一下吧!
public class MainActivity extends Activity {private ListView listview ;private ObserableList<String> listdata;private char c = 97;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listview = (ListView) findViewById(R.id.main_listview);listdata = new ObserableList<String>();IItemViewHolder viewholder = new AutoUpdataViewHolder();AutoUpdataAdapter<String> adapter = new AutoUpdataAdapter<String>(R.layout.listview_item, listdata, viewholder);listview.setAdapter(adapter);System.out.println("listview:"+listview);System.out.println("adapter:"+adapter);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {int id = item.getItemId();if (id == R.id.action_add) {listdata.add(String.valueOf(c++));System.out.println("..add.."+c);return true;}if (id == R.id.action_remove) {listdata.remove(String.valueOf(--c));System.out.println("..remove.."+c);return true;}return super.onOptionsItemSelected(item);}}
        测试的图片我就不贴,图片的使用还要多多学习,有测试成功的童鞋可以发一下.

        写了这么多,Observer再写就太多了一点,下一篇再写吧!

        



        本文资源下载:http://download.csdn.net/detail/xinxincement/9493717

0 0
原创粉丝点击