sahadev 2014-12-19 653浏览量
@Override public View getView(int position, View convertView, ViewGroup parent) { View view = inflater.inflate(R.layout.activity_main, parent, true); TextView textView = (TextView) view.findViewById(R.id.title); textView.setText(datas[position]); return view; }
好了,重点在第三行,我将Adapter的getView方法所传回的ViewGroup parent对象放置到了inflate的第二个参数中使用,inflate的第三个参数为true,面试官当时问的就是会出现什么问题,现在运行一下,看Log:
出了java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView的异常,我们看一下问题出在哪:
首先,要看从getView第三个参数回调传回来的是什么,我们来看源码:
既然是adapter与AbsListView结合使用,那getView方法一定是在AbsListView中被使用的,来找一找:
首先该怎么找呢?咱们都知道AbsListView通过setAdapter方法使两者结合,那么入口就在这里:
@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);通过第13行可以知道adapter对象是赋给了mAdapter,通过查看mAdapter是父类的属性,那咱们就需要在父类中看什么时候使用了mAdaper.getView方法:
果然找到了,在AbsListView的obtainView方法中找到了getView方法被使用的情况:
View obtainView(int position, boolean[] isScrap) { isScrap[0] = false; View scrapView; scrapView = mRecycler.getTransientStateView(position); if (scrapView != null) { return scrapView; } scrapView = mRecycler.getScrapView(position); View child; if (scrapView != null) { child = mAdapter.getView(position, scrapView, this); if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } if (child != scrapView) { mRecycler.addScrapView(scrapView, position); if (mCacheColorHint != 0) { child.setDrawingCacheBackgroundColor(mCacheColorHint); } } else { isScrap[0] = true; child.dispatchFinishTemporaryDetach(); } } else { child = mAdapter.getView(position, null, this);通过第14行和最后一行可知,它是将AbsListView的实现类传了过来。
那好,就回到 inflater.inflate(R.layout.activity_main, parent, true);这里,继续向下看:
public View inflate(int resource, ViewGroup root, boolean attachToRoot) { if (DEBUG) System.out.println("INFLATING from resource: " + resource); XmlResourceParser parser = getContext().getResources().getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } }这里调用了重载方法
inflate(parser, root, attachToRoot);在重载方法内部我们看到:
// We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { root.addView(temp, params); }
还是需要回到AbsListView.obtainView方法,通过第14行可以看到这个通过getView方法返回的View最终被obtainView弹了出去,继续看,由于在AbsListView中没有找到使用obtainView的地方,所以使用obtainView的地方应该在其子类中,果不其然(这里通过ListView做演示):
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Sets up mListPadding super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int childWidth = 0; int childHeight = 0; int childState = 0; mItemCount = mAdapter == null ? 0 : mAdapter.getCount(); if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED)) { final View child = obtainView(0, mIsScrap);
private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft, boolean selected, boolean recycled)这个方法将obtainView返回的View传了进来,最终我们可以在该方法内部看到这么一段代码,是属于ViewGroup的:
attachViewToParent(child, flowDown ? -1 : 0, p);
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
时时分享云计算技术内容,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。