适配器,作为android应用层的开发中,具有很重要的作用。在诸如ListView,gallery等sdk中提供的展示批量数据的控件中,起到一个适配数据源的作用。sdk中已经为我们提供了一个简单的并且适用性很广的适配器SimpleAdapter,该类就是继承自抽象类BaseAdapter实现的一个具体的适配器,并且能接收 List<? extends Map<String, ?>>形式的数据源格式的数据。但是很多情况下,我们使用ListView等容器的时候,往往要在渲染每一条数据的时候做一些我们自己想做的事情,此时就要实现BaseAdapter来实现自己的一个Adapter。
在进入正文之前,先说一下关于抽象类与接口的区别,以下摘自百度知道。
你选择使用接口和抽象类的依据是什么? 接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它.所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。第一点. 接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类。 第二点. 接口可以继承,抽象类不行 第三点. 接口定义方法,不能实现,而抽象类可以实现部分方法。 第四点. 接口中基本数据类型为static 而抽类象不是的。当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。 接口可以实现也可以继承,抽象类不行 抽象类的功能要远超过接口,但是,定义抽象类的代价高。因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类。在这个类中,你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度的。
上面说的很清楚了,接口是对动作的抽象,而抽象类是对根源的抽象。抽象类表示的是这个对象是什么,而接口表示的是这个对象能做什么。同时在我阅读BaseAdapter源码的时候也有些感悟,BaseAdapter是一个抽象类,它实现了ListAdapter和SpinnerAdapter接口,而这两个接口又实现了Adapter接口。我们在构造自己的Adapter的时候经常要必须实现的getCount()和getView()方法都是在Adapter接口中定义的。
在大牛们写的源码中,往往都是接口与抽象类同时使用。有关于BaseAdapter中的源码,则把最基本的一些功能(能做什么)抽象为一个接口,放在最底层,而后通过继承这个接口再抽象一些子接口,当有抽象类实现了这些子接口的时候,可以选择性的(这是抽象类允许的)实现接口中定义的功能,作为一个具有统一功能的更具体的但是同样以抽象的形式而存在,最后我们要构造这种经过抽象的类型的具体类的时候,则需要将抽象类没有实现的功能全部实现(这是必须的),甚至可以重写抽象类中已经实现的某些方法(一般情况下不必这样做),这时我们可以通过实例化我们自己构造的具体类来完成一些工作了。
这种层级关系让我体验到了从无到有的过程,也深刻的理解了什么叫抽象到具体的过程,在这种模型的基础上,我们可以从容的扩展和具象化。不必担心功能的丢失或者偏离设计此类型的初衷,由简化繁需要强大的根基,抽象类和接口的结合就是面向对象变成最强大的根基。
下面贴出源码来具体看
既然上面说到了由简化繁,那么就从最基本的接口开始
1、Adapter
1 package android.widget; 2 3 import android.database.DataSetObserver; 4 import android.view.View; 5 import android.view.ViewGroup; 6 7 /** 8 * 。。。。。。 9 */ 10 public interface Adapter { 11 /** 12 * Register an observer that is called when changes happen to the data used by this adapter. 13 * 14 * @param observer the object that gets notified when the data set changes. 15 */ 16 void registerDataSetObserver(DataSetObserver observer); 17 18 /** 19 * Unregister an observer that has previously been registered with this 20 * adapter via {@link #registerDataSetObserver}. 21 * 22 * @param observer the object to unregister. 23 */ 24 void unregisterDataSetObserver(DataSetObserver observer); 25 26 /** 27 * How many items are in the data set represented by this Adapter. 28 * 29 * @return Count of items. 30 */ 31 int getCount(); 32 33 /** 34 * Get the data item associated with the specified position in the data set. 35 * 36 * @param position Position of the item whose data we want within the adapter's 37 * data set. 38 * @return The data at the specified position. 39 */ 40 Object getItem(int position); 41 42 /** 43 * Get the row id associated with the specified position in the list. 44 * 45 * @param position The position of the item within the adapter's data set whose row id we want. 46 * @return The id of the item at the specified position. 47 */ 48 long getItemId(int position); 49 50 /** 51 * Indicates whether the item ids are stable across changes to the 52 * underlying data. 53 * 54 * @return True if the same id always refers to the same object. 55 */ 56 boolean hasStableIds(); 57 58 /** 59 * 。。。。。。 60 */ 61 View getView(int position, View convertView, ViewGroup parent); 62 63 /** 64 * An item view type that causes the {@link AdapterView} to ignore the item 65 * view. For example, this can be used if the client does not want a 66 * particular view to be given for conversion in 67 * {@link #getView(int, View, ViewGroup)}. 68 * 69 * @see #getItemViewType(int) 70 * @see #getViewTypeCount() 71 */ 72 static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE; 73 74 /** 75 * Get the type of View that will be created by {@link #getView} for the specified item. 76 * 77 * @param position The position of the item within the adapter's data set whose view type we 78 * want. 79 * @return An integer representing the type of View. Two views should share the same type if one 80 * can be converted to the other in {@link #getView}. Note: Integers must be in the 81 * range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can 82 * also be returned. 83 * @see #IGNORE_ITEM_VIEW_TYPE 84 */ 85 int getItemViewType(int position); 86 87 /** 88 * 。。。。。。 89 */ 90 int getViewTypeCount(); 91 92 static final int NO_SELECTION = Integer.MIN_VALUE; 93 94 /** 95 * @return true if this adapter doesn't contain any data. This is used to determine 96 * whether the empty view should be displayed. A typical implementation will return 97 * getCount() == 0 but since getCount() includes the headers and footers, specialized 98 * adapters might want a different behavior. 99 */ 100 boolean isEmpty(); 101 }
然后是继承自这个接口的两个接口
2、ListAdapter、SpinnerAdapter
(由于内容非常少,则粘在一起)
1 package android.widget; 2 3 /** 4 * 。。。。。。 5 */ 6 public interface ListAdapter extends Adapter { 7 8 /** 9 * 。。。。。。 10 */ 11 public boolean areAllItemsEnabled(); 12 13 /** 14 * 。。。。。。 15 */ 16 boolean isEnabled(int position); 17 } 18 19 20 21 22 package android.widget; 23 24 import android.view.View; 25 import android.view.ViewGroup; 26 27 /** 28 * Extended {@link Adapter} that is the bridge between a 29 * {@link android.widget.Spinner} and its data. A spinner adapter allows to 30 * define two different views: one that shows the data in the spinner itself and 31 * one that shows the data in the drop down list when the spinner is pressed.</p> 32 */ 33 public interface SpinnerAdapter extends Adapter { 34 /** 35 * 。。。。。。 36 */ 37 public View getDropDownView(int position, View convertView, ViewGroup parent); 38 }
这里BaseAdapter用到的是观察者模式,在ListView的setAdapter里注册一个AdapterDataSetObserver观察者,相当于在使用按钮时候,对按钮set一个OnClickListener。这里的AdapterDataSetObserver是一个内部类,这个类继承自DataSetObserver这个抽象类,并且重写了onChanged()和onInvalidated()方法,而OnClickListener则是一个接口的子类,实现了这个接口的匿名类或者是实体类,重写了OnClick()方法。
3、BaseAdapter
1 public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { 2 // 这里实例化一个观察者操作类 3 private final DataSetObservable mDataSetObservable = new DataSetObservable(); 4 5 public boolean hasStableIds() { 6 return false; 7 } 8 9 // 这里DataSetObserver是一个观察者的抽象类型 通过参数传入具体的观察者 10 public void registerDataSetObserver(DataSetObserver observer) { 11 mDataSetObservable.registerObserver(observer); 12 } 13 14 public void unregisterDataSetObserver(DataSetObserver observer) { 15 mDataSetObservable.unregisterObserver(observer); 16 } 17 18 /** 19 * Notifies the attached observers that the underlying data has been changed 20 * and any View reflecting the data set should refresh itself. 21 */ 22 public void notifyDataSetChanged() { 23 // 通过观察者操作类回调注册的观察者中用户编写的OnChanged()方法 24 mDataSetObservable.notifyChanged(); 25 } 26 27 /** 28 * Notifies the attached observers that the underlying data is no longer valid 29 * or available. Once invoked this adapter is no longer valid and should 30 * not report further data set changes. 31 */ 32 public void notifyDataSetInvalidated() { 33 mDataSetObservable.notifyInvalidated(); 34 } 35 36 public boolean areAllItemsEnabled() { 37 return true; 38 } 39 40 public boolean isEnabled(int position) { 41 return true; 42 } 43 44 public View getDropDownView(int position, View convertView, ViewGroup parent) { 45 return getView(position, convertView, parent); 46 } 47 48 public int getItemViewType(int position) { 49 return 0; 50 } 51 52 public int getViewTypeCount() { 53 return 1; 54 } 55 56 public boolean isEmpty() { 57 return getCount() == 0; 58 } 59 }
4、观察者抽象类DataSetObserver
1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.database; 18 19 /** 20 * Receives call backs when a data set has been changed, or made invalid. The typically data sets 21 * that are observed are {@link Cursor}s or {@link android.widget.Adapter}s. 22 * DataSetObserver must be implemented by objects which are added to a DataSetObservable. 23 */ 24 public abstract class DataSetObserver { 25 /** 26 * This method is called when the entire data set has changed, 27 * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}. 28 */ 29 public void onChanged() { 30 // Do nothing 31 } 32 33 /** 34 * This method is called when the entire data becomes invalid, 35 * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a 36 * {@link Cursor}. 37 */ 38 public void onInvalidated() { 39 // Do nothing 40 } 41 }
5、实现了功能的具体观察者AdapterDataSetObserver----实则是抽象类AdapterView的一个内部类,而ListView类继承自抽象类AbsListView,AbsListView继承自抽象类AdapterView,其中这两个抽象类的其他实现我们不关注,只关注有关于ListView的地方。
1 class AdapterDataSetObserver extends DataSetObserver { 2 3 private Parcelable mInstanceState = null; 4 5 @Override 6 public void onChanged() { 7 mDataChanged = true; 8 mOldItemCount = mItemCount; 9 mItemCount = getAdapter().getCount(); 10 11 // Detect the case where a cursor that was previously invalidated has 12 // been repopulated with new data. 13 if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null 14 && mOldItemCount == 0 && mItemCount > 0) { 15 AdapterView.this.onRestoreInstanceState(mInstanceState); 16 mInstanceState = null; 17 } else { 18 rememberSyncState(); 19 } 20 checkFocus(); 21 requestLayout(); 22 } 23 24 @Override 25 public void onInvalidated() { 26 mDataChanged = true; 27 28 if (AdapterView.this.getAdapter().hasStableIds()) { 29 // Remember the current state for the case where our hosting activity is being 30 // stopped and later restarted 31 mInstanceState = AdapterView.this.onSaveInstanceState(); 32 } 33 34 // Data is invalid so we should reset our state 35 mOldItemCount = mItemCount; 36 mItemCount = 0; 37 mSelectedPosition = INVALID_POSITION; 38 mSelectedRowId = INVALID_ROW_ID; 39 mNextSelectedPosition = INVALID_POSITION; 40 mNextSelectedRowId = INVALID_ROW_ID; 41 mNeedSync = false; 42 43 checkFocus(); 44 requestLayout(); 45 } 46 47 public void clearSavedState() { 48 mInstanceState = null; 49 } 50 }
6、观察者操作类的抽象类Observable<T>
为了方便阅读,删去了注释,只看方法名比较容易理解,这里主要实现的是观察者的注册,实则是在一个ArrayList中不断的添加观察者DataSetObserver实体
package android.database; import java.util.ArrayList; 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(); } } }
7、观察者操作类的具体实现DataSetObservable
可以看到,这里定义了notifyChanged方法的实现,通过同步代码块逐条的对集合中的每一条数据进行OnChanged方法调用。
1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.database; 18 19 /** 20 * A specialization of {@link Observable} for {@link DataSetObserver} 21 * that provides methods for sending notifications to a list of 22 * {@link DataSetObserver} objects. 23 */ 24 public class DataSetObservable extends Observable<DataSetObserver> { 25 /** 26 * Invokes {@link DataSetObserver#onChanged} on each observer. 27 * Called when the contents of the data set have changed. The recipient 28 * will obtain the new contents the next time it queries the data set. 29 */ 30 public void notifyChanged() { 31 synchronized(mObservers) { 32 // since onChanged() is implemented by the app, it could do anything, including 33 // removing itself from {@link mObservers} - and that could cause problems if 34 // an iterator is used on the ArrayList {@link mObservers}. 35 // to avoid such problems, just march thru the list in the reverse order. 36 for (int i = mObservers.size() - 1; i >= 0; i--) { 37 mObservers.get(i).onChanged(); 38 } 39 } 40 } 41 42 /** 43 * Invokes {@link DataSetObserver#onInvalidated} on each observer. 44 * Called when the data set is no longer valid and cannot be queried again, 45 * such as when the data set has been closed. 46 */ 47 public void notifyInvalidated() { 48 synchronized (mObservers) { 49 for (int i = mObservers.size() - 1; i >= 0; i--) { 50 mObservers.get(i).onInvalidated(); 51 } 52 } 53 } 54 }
8、最后就是ListView中setAdapter方法的实现了,小小的setAdapter方法中涉及到了BaseAdapter的引用,DataSetObserver的引用。
这里实际上是通过入参传入了我们自己实现的Adapter,一个继承自BaseAdapter的Adapter,并且在方法中已经实例化了一个上文提到的AdapterDataSetObserver,一个继承自DataSetObserver的具体观察者。
@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; // AbsListView#setAdapter will update choice mode states. super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); mDataSetObserver = new AdapterDataSetObserver();//AdapterDataSetObserver是ListView的基类AdapterView的内部类 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();//更新视图 }