深入理解ListView (1)— 一天一点源码
来源:互联网 发布:一淘是淘宝的吗 编辑:程序博客网 时间:2024/06/03 18:21
AdapterView - 一天一点源码
前言:
由图可知,ListView继承至AbsListView,AbsListView又继承至AdapterView(还实现了TextWatcher方法,往后再说)。
计划从AdapterView开始对ListView进行理解,了解ListView的实现机制。
1、说明
/** * An AdapterView is a view whose children are determined by an {@link Adapter}. */public abstract class AdapterView<T extends Adapter> extends ViewGroup {...}
AdapterView是一个带有一个Adapter子类泛型的抽象类,继承自ViewGroup。
2、方法
public AdapterView(Context context) { this(context, null);}public AdapterView(Context context, AttributeSet attrs) { this(context, attrs, 0);}public AdapterView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0);}public AdapterView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); // If not explicitly specified this view is important for accessibility. if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); }}
AdapterView的5个构造方法。
public interface OnItemClickListener { void onItemClick(AdapterView<?> parent, View view, int position, long id);}public void setOnItemClickListener(@Nullable OnItemClickListener listener) { mOnItemClickListener = listener;}@Nullablepublic final OnItemClickListener getOnItemClickListener() { return mOnItemClickListener;}
定义了item点击监听接口,实现点击监听的方法,以及获得Item的当前监听器对象的方法
public boolean performItemClick(View view, int position, long id) { final boolean result; if (mOnItemClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnItemClickListener.onItemClick(this, view, position, id); result = true; } else { result = false; } if (view != null) { view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } return result;}
如果点击监听被定义,实现点击事务。
boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id);}public void setOnItemLongClickListener(OnItemLongClickListener listener) { if (!isLongClickable()) { setLongClickable(true); } mOnItemLongClickListener = listener;}
定义长按点击事件的方法
public interface OnItemSelectedListener { void onItemSelected(AdapterView<?> parent, View view, int position, long id); void onNothingSelected(AdapterView<?> parent);}public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) { mOnItemSelectedListener = listener;}@Nullablepublic final OnItemSelectedListener getOnItemSelectedListener() { return mOnItemSelectedListener;}
定义Item选择监听的接口,Item被选择的监听方法,以及获得当前Item监听器的对象的方法。
@Overridepublic void setOnClickListener(OnClickListener l) { throw new RuntimeException("Don't call setOnClickListener for an AdapterView. " + "You probably want setOnItemClickListener instead");}
重写父类方法,设置当前AdapterView的监听。
@Overridepublic void addView(View child) { throw new UnsupportedOperationException("addView(View) is not supported in AdapterView");}@Overridepublic void addView(View child, int index) { throw new UnsupportedOperationException("addView(View, int) is not supported in AdapterView");}@Overridepublic void addView(View child, LayoutParams params) { throw new UnsupportedOperationException("addView(View, LayoutParams) " + "is not supported in AdapterView");}@Overridepublic void addView(View child, int index, LayoutParams params) { throw new UnsupportedOperationException("addView(View, int, LayoutParams) " + "is not supported in AdapterView");}
addView继承自ViewGroup,不支持调用,调用是抛出异常。
@Overridepublic CharSequence getAccessibilityClassName() { return AdapterView.class.getName();}
返回AdapterView的类名。
public abstract T getAdapter();
返回AdapterView的适配器adapter。
public abstract void setAdapter(T adapter);
设置AdapterView的适配器adapter。
@Overridepublic void removeView(View child) { throw new UnsupportedOperationException("removeView(View) is not supported in AdapterView");}@Overridepublic void removeViewAt(int index) { throw new UnsupportedOperationException("removeViewAt(int) is not supported in AdapterView");}@Overridepublic void removeAllViews() { throw new UnsupportedOperationException("removeAllViews() is not supported in AdapterView");}
重写的ViewGroup的remove方法,依次为移除指定视图,移除指定位置的视图,移除所有视图等。不可被调用,调用抛出异常。
@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) { mLayoutHeight = getHeight();}
重写的ViewGroup的方法,获得当前高度。
public long getSelectedItemId() { return mNextSelectedRowId;}
获得选中子控件的Id。
public abstract View getSelectedView();
获得选中的视图。
public Object getSelectedItem() { T adapter = getAdapter(); int selection = getSelectedItemPosition(); if (adapter != null && adapter.getCount() > 0 && selection >= 0) { return adapter.getItem(selection); } else { return null; }}
获得被选中的Item的对象。
public int getCount() { return mItemCount;}
获得Item的数量。
public int getPositionForView(View view) { View listItem = view; try { View v; while ((v = (View) listItem.getParent()) != null && !v.equals(this)) { listItem = v; } } catch (ClassCastException e) { // We made it up to the window without find this list view return INVALID_POSITION; } if (listItem != null) { // Search the children for the list item final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { if (getChildAt(i).equals(listItem)) { return mFirstPosition + i; } } } // Child not found! return INVALID_POSITION;}
传入一个视图,返回传入视图的位置。
public int getFirstVisiblePosition() { return mFirstPosition;}
返回适配器设置的屏幕上可显示第一个Item的位置。
public int getLastVisiblePosition() { return mFirstPosition + getChildCount() - 1;}
返回适配器设置的屏幕上可显示的最后一个Item的位置。
public abstract void setSelection(int position);
设置当前选择条目。
public void setEmptyView(View emptyView) { mEmptyView = emptyView; // If not explicitly specified this view is important for accessibility. if (emptyView != null && emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { emptyView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } final T adapter = getAdapter(); final boolean empty = ((adapter == null) || adapter.isEmpty()); updateEmptyStatus(empty);}
设置空视图。
public View getEmptyView() { return mEmptyView;}
获得当前AdapterView的空视图对象。
private void updateEmptyStatus(boolean empty) { if (isInFilterMode()) { empty = false; } if (empty) { if (mEmptyView != null) { mEmptyView.setVisibility(View.VISIBLE); setVisibility(View.GONE); } else { // If the caller just removed our empty view, make sure the list view is visible setVisibility(View.VISIBLE); } // We are now GONE, so pending layouts will not be dispatched. // Force one here to make sure that the state of the list matches // the state of the adapter. if (mDataChanged) { this.onLayout(false, mLeft, mTop, mRight, mBottom); } } else { if (mEmptyView != null) mEmptyView.setVisibility(View.GONE); setVisibility(View.VISIBLE); }}
设置空视图的可见状态。
public Object getItemAtPosition(int position) { T adapter = getAdapter(); return (adapter == null || position < 0) ? null : adapter.getItem(position);}传入一个Item位置,获得Adapter中Item对应的数据public long getItemIdAtPosition(int position) { T adapter = getAdapter(); return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position);}
传入Item的位置,获得Adapter中Item对应的位置
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_POSITI结结结结结结N; mSelectedRowId = INVALID_ROW_ID; mNextSelectedPosition = INVALID_POSITION; mNextSelectedRowId = INVALID_ROW_ID; mNeedSync = false; checkFocus(); requestLayout(); } public void clearSavedState() { mInstanceState = null; }}
定义内部类,为AdapterView设置观察者,通过重写的onChange,onInvalidated,clearSavedState,对Adapter的状态及参数进行观察,实时做出相应改变。
总结
以上并不是AdapterView的全部源码,只是将我觉得重要的源码,以及一些在ListView中有体现的源码进行了阅读。
粗略感觉AdapterView已实现了Listview的大部分基础功能。
AdapterView中定义了设置ListView中item监听的各种方法,以及设置Adapter,内部内继承观察者类,对数据进行监控…等等。
一点一点的理解,逐步了解ListView的实现机制。
- 深入理解ListView (1)— 一天一点源码
- 深入理解ListView(2) — 一天一点源码
- 深入了解ListView(3) — 一天一点源码
- 一天读一点:《深入理解计算机系统》
- ListView深入理解
- 一天一点做项目(1)
- 深入理解OkHttp源码(一)——提交请求
- 深入理解OkHttp源码(二)——获取响应
- 深入理解OkHttp源码(三)——网络操作
- 深入理解OkHttp源码(四)——缓存
- 深入源码理解HashMap
- 深入源码理解FragmentPagerAdapter
- 深入理解BaseAdapter与ListView
- 一天一点python(FAQ-1)
- 刷了一天的《深入理解计算机系统》
- 《深入理解java虚拟机》第一章一点细节
- 《深入理解Linux内核》读书笔记1 --- 对内核的一点理解
- 一天一点Android知识之intent(1)
- Poj 2524 Ubiquitous Religions (并查集
- [POJ 3168 Treats for the Cows]区间dp
- Git工具的安装和日常使用
- spacevim - 一个模块化的,可扩展的vim配置,支持多种语言开发
- Java泛型的转型
- 深入理解ListView (1)— 一天一点源码
- 设计模式之禅笔记7--代理模式
- window下安装docker
- HDU 2577 How to Type
- 用JS获取地址栏参数的方法(超级简单)
- 标记-清除
- 无符号256位整数运算
- Jenkins构建Android项目持续集成之系统配置篇
- 【LeetCode】 375. Guess Number Higher or Lower II