zoukankan      html  css  js  c++  java
  • Android从源码看ListView的重用机制

    不管是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 stub
    mContext = context;
    inflater = LayoutInflater.from(mContext);
    }
    
    @Override
    public int getCount() {
    // TODO Auto-generated method stub
    return listString.size();
    }
    
    @Override
    public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return listString.get(arg0);
    }
    
    @Override
    public long getItemId(int position) {
    // TODO Auto-generated method stub
    return 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);
    		}
    		@Override
    		public int getCount() {
    			// TODO Auto-generated method stub
    			return mData.size();
    		}
    
    
    		@Override
    		public Object getItem(int arg0) {
    			// TODO Auto-generated method stub
    			return null;
    		}
    
    
    		@Override
    		public long getItemId(int arg0) {
    			// TODO Auto-generated method stub
    			return 0;
    		}
    
    
    		@Override
    		public 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() {
    				
    				@Override
    				public 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的数据处理。

    这是一个抽象类,不多说了。

    未完待续。

    。。

  • 相关阅读:
    node03- NODE入门
    node02- NPM的使用
    node01- 初识、特点、
    Linux中的split命令,文件切割
    修改jar包中文件
    ByteBuf 使用
    Stream的flatmap与map异同的理解
    h5底部输入框被键盘遮挡问题
    div给我画条龙
    contains 了解
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7123089.html
Copyright © 2011-2022 走看看