关于ListView的getItemViewType()这个方法的踩坑叙述
来源:互联网 发布:软件企业证书有效期 编辑:程序博客网 时间:2024/05/01 21:34
有时候我们需要做一个类似下图的列表,如下,每隔几个item就需要一个标签来区分不同的数据类型,这个时候就需要用到getItemViewType()来做区分了
BaseAdapter中有2个方法:
1.getItemViewType(int position);//得到当前item的类型
2.getViewTypeCount()//得到不同的item的总数,下面图上的类型是2种
//下面贴一段代码(因为完整的项目需要关系很多代码,所以只贴Adapter的代码)
package com.yy.ent.mobile.ui.live.livelist;import android.content.Context;import android.content.Intent;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.TextView;import com.yy.ent.cherry.Cherry;import com.yy.ent.cherry.ext.image.CircleImageView;import com.yy.ent.cherry.ext.image.ImageConfig;import com.yy.ent.cherry.ext.image.ImageManager;import com.yy.ent.cherry.ext.image.RecycleImageView;import com.yy.ent.mobile.entity.livelist.Lives;import com.yy.ent.mobile.ui.base.XBaseAdapter;import com.yy.ent.mobile.ui.live.widget.RayRelative;import com.yy.ent.mobile.ui.personal.OthersActivity;import com.yy.ent.mobile.ui.util.NavigationUtils;import com.yy.ent.mobile.ui.util.StringUtils;import com.yy.ent.mobile.ui.util.ViewHelper;import com.yy.ent.show.ui.R; public class ShowLiveAdapter extends XBaseAdapter<Lives> { public static final String MOBILE_LIVE_ITEM_CLICK = "mobile_live_item_click"; private static final int VIEW_COUNT = 2; public static final int LIVE_HEADER = 0; public static final int LIVE_CONTENT = 1; public static final int HEADER_TAG = 110; private String TAG = ShowLiveAdapter.class.getSimpleName(); public ShowLiveAdapter(Context context, int resource) { super(context, resource); } @Override public int getItemViewType(int position) { if (list.get(position).status == HEADER_TAG) { return LIVE_HEADER; } else { return LIVE_CONTENT; } } @Override public int getViewTypeCount() { return VIEW_COUNT; } @Override public View getYView(int i, View itemView, ViewGroup viewGroup) { ViewHolder holder = null; int type = getItemViewType(i); if (itemView == null) { switch (type) { case LIVE_HEADER: TextView hot = new TextView(context); hot.setText("热门直播:"); hot.setTextColor(context.getResources().getColor(R.color.link_color));// if (list.size() <= 1) {// hot.setVisibility(View.GONE);// }else {// hot.setVisibility(View.VISIBLE);// } itemView = hot; break; case LIVE_CONTENT: itemView = listContainer.inflate(itemViewResource, null); holder = new ViewHolder(); holder.anchorNick = (TextView) itemView.findViewById(R.id.live_author); holder.liveTitle = (TextView) itemView.findViewById(R.id.live_title); holder.liveAddress = (TextView) itemView.findViewById(R.id.live_address); holder.head = (CircleImageView) itemView.findViewById(R.id.live_head); holder.liveGuset = (TextView) itemView.findViewById(R.id.live_guest_num); holder.jobTag = (LinearLayout) itemView.findViewById(R.id.live_job_tag); holder.liveCover = (RecycleImageView) itemView.findViewById(R.id.live_work_cover); holder.cutTime = (TextView) itemView.findViewById(R.id.live_cut_time); holder.liveProgress = (RayRelative) itemView.findViewById(R.id.live_time_progress); itemView.setTag(holder); break; } } else { if (type == LIVE_CONTENT) { holder = (ViewHolder) itemView.getTag(); } } if (type == LIVE_CONTENT) { Lives lives = list.get(i); holder.cutTime.setText(StringUtils.formatTime(lives.countdown)); holder.liveGuset.setText(lives.online + "人在观看"); holder.anchorNick.setText(lives.anchorNick); holder.liveTitle.setText(lives.title); holder.liveAddress.setText(lives.location); ImageManager.instance().loadImage(lives.anchorAvatar, holder.head, ImageConfig.defaultImageConfig(), R.drawable.video_default_cover); ImageManager.instance().loadImage(lives.coverUri, holder.liveCover, getWidth(), 300, R.drawable.video_default_cover); if (holder.jobTag.getChildCount() > 0) { holder.jobTag.removeAllViews(); } for (int j = 0; j < lives.liveTag.length; j++) { TextView tv = (TextView) listContainer.inflate(R.layout.layout_label, holder.jobTag, false); tv.setText(lives.liveTag[j]); holder.jobTag.addView(tv); } holder.liveProgress.setProgress(getProgress(lives.liveDuration, lives.countdown)); ItemOnClick onClick = new ItemOnClick(lives); holder.liveCover.setOnClickListener(onClick); holder.head.setOnClickListener(onClick); } return itemView; } private int getProgress(long liveDuration, long countdown) { float rate = (float)countdown/ liveDuration ; int width = getWidth(); int progress = (int) (width * rate); return progress; } public int getWidth() { return ViewHelper.getDisplayMetrics(context).widthPixels; } class ItemOnClick implements View.OnClickListener { private Lives item; ItemOnClick(Lives item) { this.item = item; } @Override public void onClick(View view) { if (view.getId() == R.id.live_work_cover) { if (StringUtils.canClick()) { if (item.status == 0) { Cherry.notityUI(MOBILE_LIVE_ITEM_CLICK, item); } else { NavigationUtils.startToLiveReviewActivity(context, item ); } } } if (view.getId() == R.id.live_head) { Intent intent = new Intent(context, OthersActivity.class); intent.putExtra("personal_activity_arg_uid", item.anchorId + ""); context.startActivity(intent); } } } class ViewHolder { public RayRelative liveProgress; public TextView liveTitle; public TextView liveAddress; public CircleImageView head; public RecycleImageView liveCover; public LinearLayout jobTag; public TextView liveGuset; public TextView cutTime; public TextView anchorNick; }}
如上,有2个常量参数LIVE_HEADER和LIVE_CONTENT,它们分别代表了2种item的类型,再看看它们的值分别是0和1,注意:这里的值必须是0和1,不能大于1,也不能为其他的数字,如2,3,0x1等等,否则你在getItemViewType()的时候就会报java.lang.ArrayIndexOutOfBoundsException这个异常,因为你的getViewTypeCount返回的数量是2,所以只能有2种类型,也就是0或者1,如果你的类型设置为2或者3,就会超出了类型数量, 至于具体原因就要看看android系统的源码了.
如果出现异常,这个时候报的异常是这样的(只贴了主要的异常部分):
java.lang.ArrayIndexOutOfBoundsException: length=2; index=10 at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:6792) at android.widget.ListView.measureHeightOfChildren(ListView.java:1275) at android.widget.ListView.onMeasure(ListView.java:1175) at com.yy.ent.mobile.ui.widget.FixListView.onMeasure(FixListView.java:35)然后依次定位最下面的35行,到super.onMeasure(widthMeasureSpec, expandSpec);这行代码,也就是测量item的大小时异常
然后是ListView内部的onMeasure()方法:
@Override 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); measureScrapChild(child, 0, widthMeasureSpec); childWidth = child.getMeasuredWidth(); childHeight = child.getMeasuredHeight(); childState = combineMeasuredStates(childState, child.getMeasuredState()); if (recycleOnMeasure() && mRecycler.shouldRecycleViewType( ((LayoutParams) child.getLayoutParams()).viewType)) { mRecycler.addScrapView(child, 0); } } if (widthMode == MeasureSpec.UNSPECIFIED) { widthSize = mListPadding.left + mListPadding.right + childWidth + getVerticalScrollbarWidth(); } else { widthSize |= (childState&MEASURED_STATE_MASK); } if (heightMode == MeasureSpec.UNSPECIFIED) { heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2; } if (heightMode == MeasureSpec.AT_MOST) { // TODO: after first layout we should maybe start at the first visible position, not 0 heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1); } setMeasuredDimension(widthSize , heightSize); mWidthMeasureSpec = widthMeasureSpec; }这里计算listview的没一个item的高度,宽度,请看最下面的倒数第3行代码:measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);//测量子控件的宽高,然后经过一系列的方法及接口调用(这里楼主偷懒,代码太多啦)就会走到AbsListView的getScrapView(int position) 这个方法,这里就是最终得到的item的view类型.
到这个方法里面去
/** * @return A view from the ScrapViews collection. These are unordered. */ View getScrapView(int position) { if (mViewTypeCount == 1) { return retrieveFromScrap(mCurrentScrap, position); } else { final int whichScrap = mAdapter.getItemViewType(position); if (whichScrap >= 0 && whichScrap < mScrapViews.length) { return retrieveFromScrap(mScrapViews[whichScrap], position); } } return null; }
看到mAdapter.getItemViewType(position)这行代码了吗,其中的position就是你传入的item的下标,返回值就是你之前定义的类型0,1,再看看下面的if判断是不是就一目了然了,其实mScrapViews.length=getViewTypeCount(),所以你这里如果传入是3,4的话,if条件就不会成立了,view也就无法进行绘制,mScrapViews是一个ArrayList,取到的值大于getViewTypeCount(),那么就会造成数组越界了.
因为凭自己的感觉去定义了ItemViewType的类型值,所以列表一直报错,这里为了防止其他和我一样踩坑的人不知所云,特意记录下来,后面的看不懂没关系,只要注意前面红色标记的位置就可以了
0 0
- 关于ListView的getItemViewType()这个方法的踩坑叙述
- ListView getItemViewType ArrayIndexOutOfBoundsException 的解决办法
- Android ListView的不同样式,getItemViewType,getViewTypeCount
- ListView分析和getItemViewType的用法
- Android之ListView的getItemViewType和getViewTypeCount
- listView分类型,getItemViewType()的用法
- Android之ListView的getItemViewType和getViewTypeCount
- 关于解释系统的叙述
- ListView和BaseAdapter的getViewTypeCount和getItemViewType方法实现Gridview,显示多列
- getItemViewType为Listview的item设置不同的布局
- 关于 c++ 中各类指针的叙述
- 关于本人博客的一些叙述
- 关于scanf的返回值叙述。
- ListView 使用BaseAdapter时的getItemViewType 和 getViewTypeCount作用
- Android ListView适配器BaseAdapter中getItemViewType需要注意的问题
- Android ListView Adapter的getItemViewType和getViewTypeCount多种布局
- Android ListView Adapter的getItemViewType和getViewTypeCount多种布局
- Adapter的getViewTypeCount和getItemViewType及-ListView/GridView
- JavaScript cookie存储和读取(一)
- Spring中idref与ref的区别
- c++快速简易入门教程_002构造函数
- H5修改url之pushState()和页面下拉加载判断
- nrf51822 --- 配对绑定输入密码(pair)
- 关于ListView的getItemViewType()这个方法的踩坑叙述
- c++快速简易入门教程_003析构函数
- 【HDU】 1028 Ignatius and the Princess III
- Leetcode_86_Partition List
- 使用SQL Server发布数据库快照遇到错误:对路径”xxxxx“访问被拒绝的解决方法
- Android中复制及粘贴功能
- 如何用js得到当前页面的url信息方法(JS获取当前网址信息)
- java单例模式使用及注意事项
- dumpsys