ListView中使用自定义Adapter及时更新数据
又到10点半,时间真是过的真快。在项目中,遇到不能ListView及时更新的问题。写了一个demo,其中也遇到一些问题,一并写出来。前几个月总是有点懒,但是这个月总算是凑够4篇了。
代码比较简单,遇到点简单的问题,弄到了现在。
好吧,上代码:
public class PersonAdapter extends BaseAdapter {private ArrayList<PersonBean> mList;private Context mContext;public PersonAdapter(ArrayList<PersonBean> list, Context context) {mList = list;mContext = context;}public void refresh(ArrayList<PersonBean> list) {mList = list;notifyDataSetChanged();}@Overridepublic int getCount() {return mList.size();}@Overridepublic Object getItem(int position) {return mList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {Holder holder = null;if (convertView == null) {LayoutInflater inflater = LayoutInflater.from(mContext);convertView = inflater.inflate(R.layout.list_item, null);holder = new Holder();holder.mNameText = (TextView)convertView.findViewById(R.id.name_text);holder.mIDText = (TextView)convertView.findViewById(R.id.id_text);convertView.setTag(holder);} else {holder = (Holder) convertView.getTag();}holder.mNameText.setText(mList.get(getCount() - position - 1).getName());holder.mIDText.setText(mList.get(getCount() - position - 1).getID());return convertView;}class Holder {private TextView mNameText, mIDText;}}public void refresh(ArrayList<PersonBean> list) {mList = list;notifyDataSetChanged();}public PersonAdapter(ArrayList<PersonBean> list, Context context) {mList = list;mContext = context;}下面看一下主Activity:
public class ListViewRefreshActivity extends Activity {private ListView mListView;private ArrayList<PersonBean> mList;private PersonAdapter mAdapter;private Handler mHandler;private String mName, mID;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mListView = (ListView)findViewById(R.id.listView);mList = new ArrayList<PersonBean>();mAdapter = new PersonAdapter(mList, ListViewRefreshActivity.this);mListView.setAdapter(mAdapter);mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);mList.add((PersonBean) msg.obj);Log.v("@@@@@@", "this is get message");mAdapter.refresh(mList);//mAdapter.notifyDataSetChanged();}};//final Message message = new Message();new Thread(new Runnable() {@Overridepublic void run() {try {for (int i = 0; i < 10; i++) {mName = "hao :" + i;mID = "" + i;PersonBean bean = new PersonBean();bean.setID(mID);bean.setName(mName);Message message = new Message();message.obj = bean;Thread.sleep(3000);mHandler.sendMessage(message);//mHandler.sendMessageDelayed(message, 10000);}}catch (Exception e) {e.printStackTrace();}}}).start();}}先说一个小bug吧,看一下在new Thread上面有一句注释掉的final Message message = new Message();
message = mHandler.obtainMessage();里面主要看一下handler中重写handlerMessage这个方法:
@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);mList.add((PersonBean) msg.obj);Log.v("@@@@@@", "this is get message");mAdapter.refresh(mList);//mAdapter.notifyDataSetChanged();}notifyDataSetChanged这个方法的设计是典型观察者模式。看一下源代码:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { private final DataSetObservable mDataSetObservable = new DataSetObservable(); public boolean hasStableIds() { return false; } public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } /** * Notifies the attached observers that the underlying data has been changed * and any View reflecting the data set should refresh itself. */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } /** * Notifies the attached observers that the underlying data is no longer valid * or available. Once invoked this adapter is no longer valid and should * not report further data set changes. */ public void notifyDataSetInvalidated() { mDataSetObservable.notifyInvalidated(); }/** * Invokes onChanged on each observer. Called when the data set being observed has * changed, and which when read contains the new state of the data. */ public void notifyChanged() { synchronized(mObservers) { // since onChanged() is implemented by the app, it could do anything, including // removing itself from {@link mObservers} - and that could cause problems if // an iterator is used on the ArrayList {@link mObservers}. // to 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(); } } }mObservers的定义如下:
protected final ArrayList<T> mObservers = new ArrayList<T>();
前面说到了,我们可以调用registerDataSetObserver注册为观察者,但是是在哪注册的呢?因为如果没有注册,adapter就不应该发生变化。所以,我们看下ListView的SetAdapter这个方法:
@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(); 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(); }如果mAdapter和mDataSetObserver都不为空的话,取消mAdapter对mDataSetObserver的注册。if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); }然后,把传入的adapter这个参数,赋值给mAdapter: if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; }if (mAdapter != null) { mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver);至此,思路应该清晰了:在listview的setAdapter中把adapter注册为mDataSetObserver的观察者。当数据变化时,就可以调用notifyDataSetChanged方法来提示观察者数据已经变化。
关于观察者的详细情况:浅学设计模式之观察者<Observer>模式及在android中的应用
最后就是说一下,里面PersonBean类,就是一个实体类,很简单,不在详述。
最后,源代码:http://download.csdn.net/detail/aomandeshangxiao/4704585