Android從源碼看ListView的重用機制

來源:互聯網
上載者:User

標籤: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的重用機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.