標籤:case tac stopped data 複雜 inflate generated ack rowid
不管是android還是iOS,列表視圖應該是最複雜的控制項了。android中的listview從命名能夠看出是個一維數組,而iOS中的tableview則是二維數組。但事實上須要注意的地方是差點兒相同的。都是重用機制。這是考量你對listview是否能掌握的最好的方法。
常見的listview的初始化以及設定適配器的代碼例如以下:
ListView listView;MyAdapter listAdapter;ArrayList<String> listString;listView = (ListView)this.findViewById(R.id.listview);listString = new ArrayList<String>();for(int i = 0 ; i < 100 ; i++){listString.add(Integer.toString(i));}listAdapter = new MyAdapter(this);listView.setAdapter(listAdapter);}class MyAdapter extends BaseAdapter{Context mContext;LinearLayout linearLayout = null;LayoutInflater inflater;public MyAdapter(Context context) {// TODO Auto-generated constructor stubmContext = context;inflater = LayoutInflater.from(mContext);}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn listString.size();}@Overridepublic Object getItem(int arg0) {// TODO Auto-generated method stubreturn listString.get(arg0);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}public final class ViewHolder{public ImageView img;public TextView title;public TextView info;public Button viewBtn;}public class MyAdapter extends BaseAdapter{private LayoutInflater mInflater;public MyAdapter(Context context){this.mInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn mData.size();}@Overridepublic Object getItem(int arg0) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int arg0) {// TODO Auto-generated method stubreturn 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;if (convertView == null) {holder=new ViewHolder(); convertView = mInflater.inflate(R.layout.vlist2, null);holder.img = (ImageView)convertView.findViewById(R.id.img);holder.title = (TextView)convertView.findViewById(R.id.title);holder.info = (TextView)convertView.findViewById(R.id.info);holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);convertView.setTag(holder);}else {holder = (ViewHolder)convertView.getTag();}holder.img.setBackgroundResource((Integer)mData.get(position).get("img"));holder.title.setText((String)mData.get(position).get("title"));holder.info.setText((String)mData.get(position).get("info"));holder.viewBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {showInfo();}});return convertView;}}
當中setAdapter是主要用來設定資料的。我們不防看一下ListView(原始碼在此)的setAdapter原始碼
@Override public void setAdapter(ListAdapter adapter) { if (null != mAdapter) { 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; 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(); } if (mCheckStates != null) { mCheckStates.clear(); } requestLayout(); }
從以上代碼能夠看出其分為兩步,第一步是當前adapter不為空白的話。先清空本地adapter資料。然後是設定新的資料到listview。
當中裡面有個重要的類
AdapterDataSetObserver
是用來儲存資料的,我們看一下裡面的代碼,有個成員變數
mDataSetObserver
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">就是這個對象申明在listview的父類AbsListView(<a target=_blank href="http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/widget/AbsListView.java/?v=source">原始碼在此</a>)中</span>
那麼這個AdapterDataSetObserver到底是個什麼東西呢,我們還是到AbsListView的父類AdapterView(原始碼在此)中一探到底吧。
class AdapterDataSetObserver extends DataSetObserver { private Parcelable mInstanceState = null; @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; mItemCount = getAdapter().getCount(); // Detect the case where a cursor that was previously invalidated has // been repopulated with new data. if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null && mOldItemCount == 0 && mItemCount > 0) { AdapterView.this.onRestoreInstanceState(mInstanceState); mInstanceState = null; } else { rememberSyncState(); } checkFocus(); requestLayout(); } @Override public void onInvalidated() { mDataChanged = true; if (AdapterView.this.getAdapter().hasStableIds()) { // Remember the current state for the case where our hosting activity is being // stopped and later restarted mInstanceState = AdapterView.this.onSaveInstanceState(); } // Data is invalid so we should reset our state mOldItemCount = mItemCount; mItemCount = 0; mSelectedPosition = INVALID_POSITION; mSelectedRowId = INVALID_ROW_ID; mNextSelectedPosition = INVALID_POSITION; mNextSelectedRowId = INVALID_ROW_ID; mNeedSync = false; checkSelectionChanged(); checkFocus(); requestLayout(); } public void clearSavedState() { mInstanceState = null; } }
從以上代碼能夠看出,這個類事實上是繼承自DataSetObserver(原始碼在此)。
使用的是觀察者模式,用於listview的資料處理。
這是一個抽象類別,不多說了。
未完待續。
。。
Android從源碼看ListView的重用機制