And then to, the time is really fast. In the project, the problem that the listview cannot be updated in time is encountered. I wrote a demo, which also encountered some problems. I have been a little lazy for the past few months, but this month is enough for four articles.
The code is relatively simple. I encountered some simple problems and got it now.
Okay, go to the Code:
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;}}
The personadapter inherits from the baseadapter, and the code in it should be familiar. Note This code:
public void refresh(ArrayList<PersonBean> list) {mList = list;notifyDataSetChanged();}
When initializing the personadapter, You need to import an external MList.
public PersonAdapter(ArrayList<PersonBean> list, Context context) {mList = list;mContext = context;}
When madapter. yydatasetchanged () is used in an activity, data cannot be updated in a timely manner. At this time, we need to call the refresh () method.
Let's take a look at the main 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();}}
Let's talk about a small bug first. Let's take a look at the comment on the new thread.
final Message message = new Message();
If this message is used, comments the message in the run method body, and runs the program, Android will be reported when the fourth message is sent on our machine. util. androidruntimeexception: this message is already in use. The message has been used. Therefore, a new message must be created every time a message is sent. You can also use the following statement:
message = mHandler.obtainMessage();
Here we mainly look at handler's method of overwriting 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();}
Of course, in this small example, madapter is used. refresh is more troublesome. You can call yydatasetchange directly to achieve the effect. If your code cannot achieve the effect, you can use madapter. refresh.
Notifydatasetchanged is a typical observer mode. Let's take a look at the source code:
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(); }
There is a data observer: mdatasetobservable. Notify the observer when the data of the observer changes. We use registerdatasetobserver to register the observer. Call the yydatasetchanged method. It is to tell the observer that the data has changed. In this method, the notifychanged method of datasetobserveable is called:
/** * 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(); } } }
Let's take a look at his method Description: when the data is observed to have changed, call the onchanged method of each observer to read the latest data status.
The definition of mobservers is as follows:
protected final ArrayList<T> mObservers = new ArrayList<T>();
Each Observer is notified by traversing an arraylist.
As mentioned above, we can call registerdatasetobserver to register as an observer, but where is it registered? The Adapter should not change if it is not registered. So let's take a look at the setadapter method of listview:
@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(); }
If neither madapter nor mdatasetobserver is empty, cancel madapter's registration of mdatasetobserver.
if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); }
Then, assign the input adapter parameter to madapter:
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; }
After the assignment is successful:
if (mAdapter != null) { mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver);
Assign a value to mdatasetobserver again, and register madapter as the observer of mdatasetobserver.
Now, the idea should be clear: register the adapter as the observer of mdatasetobserver in the setadapter of listview. When the data changes, you can call the notifydatasetchanged method to prompt that the observer data has changed.
Observer details: Introduction to the observer <observer> mode of design patterns and Its Application in Android
Finally, the personbean class is an entity class, which is very simple and not detailed in detail.
Final, source code: http://download.csdn.net/detail/aomandeshangxiao/4704585