ListView ViewHolder 组件返回 null Android
ListView ViewHolder components returning null Android
我已经为我的 Listview 实现了 ViewHolder 模式,如下所示:-
public class HomeListAdapter : BaseAdapter
{
public HomeListAdapter(List<Models.MyModel> myList, Activities.HomeActivity homeActivity)
{
// TODO: Complete member initialization
this.myList = myList;
this.homeActivity = homeActivity;
prefs = PreferenceManager.GetDefaultSharedPreferences(homeActivity);
inflater = LayoutInflater.FromContext(homeActivity);
}
public override int Count
{
get { return myList.Count; }
}
public override int ViewTypeCount
{
get
{
return 2;
}
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return 0;
}
public override int GetItemViewType(int position)
{
if (position == 0 || position == 1)
{
return 1;
}
else
{
return 2;
}
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View rootView = convertView;
MyViewHolder mHolder;
var mData = myList[position];
int item = GetItemViewType(position);
if(rootView ==null)
{
mHolder = new MyViewHolder(); ;
switch(item)
{
case 1:
rootView = homeActivity.LayoutInflater.Inflate(Resource.Layout.phone_home_big_row2, null);
mHolder.txtDate = convertView.FindViewById<TextView>(Resource.Id.txtDate);
mHolder.txtTitle = convertView.FindViewById<TextView>(Resource.Id.txtTitle);
mHolder.txtDetail = convertView.FindViewById<TextView>(Resource.Id.txtDetail);
mHolder.imgPlaceholderImage = convertView.FindViewById<ImageView>(Resource.Id.imgPlaceholderImage);
mHolder.txtCategory = convertView.FindViewById<TextView>(Resource.Id.txtCategory);
break;
case 2:
rootView = homeActivity.LayoutInflater.Inflate(Resource.Layout.phone_home_list_row, null);
mHolder.txtTitle = convertView.FindViewById<TextView>(Resource.Id.txtTitle);
mHolder.txtDate = convertView.FindViewById<TextView>(Resource.Id.txtDate);
mHolder.viewColor = convertView.FindViewById<View>(Resource.Id.viewColor);
mHolder.imgPlaceholderImage = convertView.FindViewById<ImageView>(Resource.Id.imgPlaceholderImage);
break;
}
rootView.Tag = mHolder;
}
else
{
mHolder = (MyViewHolder)rootView.Tag;
}
switch(item)
{
case 1:
mHolder.txtTitle.Text = mData.Title;
if (mHolder.txtDetail != null)
{
mHolder.txtDetail.Text = mData.BodyText;
mHolder.txtDetail.Ellipsize = TextUtils.TruncateAt.End;
mHolder.txtDetail.SetMaxLines(3);
mHolder.txtDetail.SetTextColor(Color.Black);
}
if (mHolder.txtCategory != null)
{
mHolder.txtCategory.Text = mData.NewsSourceTitle;
mHolder.txtCategory.SetTextColor(Color.White);
mHolder.txtCategory.SetBackgroundColor(Color.ParseColor(mData.Color));
}
if (!string.IsNullOrEmpty(mData.PublishedDate))
{
mHolder.txtDate.Text = DateTime.Parse(mData.PublishedDate).ToString("dd MMMM yyyy", CultureInfo.InvariantCulture);
}
break;
case 2:
mHolder.txtTitle.Text = mData.Title;
if (mHolder.viewColor != null)
{
mHolder.viewColor.SetBackgroundColor(Color.ParseColor(mData.Color));
}
if (!string.IsNullOrEmpty(mData.PublishedDate))
{
mHolder.txtDate.Text = DateTime.Parse(mData.PublishedDate).ToString("dd MMMM yyyy", CultureInfo.InvariantCulture);
}
break;
}
return rootView;
}
public class MyViewHolder : Java.Lang.Object
{
public TextView txtTitle { get; set;}
public TextView txtDate{ get; set;}
public TextView txtDetail{ get; set;}
public ImageView imgPlaceholderImage { get; set; }
public View viewColor { get; set; }
public TextView txtCategory { get; set; }
}
}
}
但我总是 mHolder.txtTitle 并且其他组件为 null,即使 mHolder 不为 null。我需要根据它们 positions.Is 来膨胀两种不同的布局 我做错了什么?任何帮助表示赞赏。谢谢
首先,您应该 return getItem 覆盖方法中特定位置的项目
public override Java.Lang.Object GetItem(int position)
{
return myList(position);
}
出现您的问题是因为您的代码有时引用 rootView
,有时引用 convertView
。
在这一行中,您在 convertView
上执行 findViewByID()
:
mHolder.txtTitle=convertView.FindViewById<TextView>(Resource.Id.txtTitle);
但是,您从未检查过 convertView
是否为空,如果是则为其分配新的 View
。相反,您创建了一个对 convertView
的新引用,您将其称为 rootView
,检查 that 是否为 null,如果是,则您分配了一个新的 View
到 rootView。因此,rootView
现在是非空的,但 convertView
仍然是。
public override View GetView(int position,View convertView,ViewGroup parent)
{
View rootView=convertView;
//...
if(rootView==null)
{
mHolder=new MyViewHolder();;
switch(item)
{
case 1:
rootView = homeActivity.LayoutInflater.Inflate(Resource.Layout.phone_home_big_row2,null);
mHolder.txtDate=convertView.FindViewById<TextView>(Resource.Id.txtDate);
// ^^^^^^^^^^ convertView can still be null!!!
//...
}
我建议您删除代码中对 rootView
的所有引用,直接使用 convertView
。这就是将它提供给您的方法的原因。
我已经为我的 Listview 实现了 ViewHolder 模式,如下所示:-
public class HomeListAdapter : BaseAdapter
{
public HomeListAdapter(List<Models.MyModel> myList, Activities.HomeActivity homeActivity)
{
// TODO: Complete member initialization
this.myList = myList;
this.homeActivity = homeActivity;
prefs = PreferenceManager.GetDefaultSharedPreferences(homeActivity);
inflater = LayoutInflater.FromContext(homeActivity);
}
public override int Count
{
get { return myList.Count; }
}
public override int ViewTypeCount
{
get
{
return 2;
}
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return 0;
}
public override int GetItemViewType(int position)
{
if (position == 0 || position == 1)
{
return 1;
}
else
{
return 2;
}
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View rootView = convertView;
MyViewHolder mHolder;
var mData = myList[position];
int item = GetItemViewType(position);
if(rootView ==null)
{
mHolder = new MyViewHolder(); ;
switch(item)
{
case 1:
rootView = homeActivity.LayoutInflater.Inflate(Resource.Layout.phone_home_big_row2, null);
mHolder.txtDate = convertView.FindViewById<TextView>(Resource.Id.txtDate);
mHolder.txtTitle = convertView.FindViewById<TextView>(Resource.Id.txtTitle);
mHolder.txtDetail = convertView.FindViewById<TextView>(Resource.Id.txtDetail);
mHolder.imgPlaceholderImage = convertView.FindViewById<ImageView>(Resource.Id.imgPlaceholderImage);
mHolder.txtCategory = convertView.FindViewById<TextView>(Resource.Id.txtCategory);
break;
case 2:
rootView = homeActivity.LayoutInflater.Inflate(Resource.Layout.phone_home_list_row, null);
mHolder.txtTitle = convertView.FindViewById<TextView>(Resource.Id.txtTitle);
mHolder.txtDate = convertView.FindViewById<TextView>(Resource.Id.txtDate);
mHolder.viewColor = convertView.FindViewById<View>(Resource.Id.viewColor);
mHolder.imgPlaceholderImage = convertView.FindViewById<ImageView>(Resource.Id.imgPlaceholderImage);
break;
}
rootView.Tag = mHolder;
}
else
{
mHolder = (MyViewHolder)rootView.Tag;
}
switch(item)
{
case 1:
mHolder.txtTitle.Text = mData.Title;
if (mHolder.txtDetail != null)
{
mHolder.txtDetail.Text = mData.BodyText;
mHolder.txtDetail.Ellipsize = TextUtils.TruncateAt.End;
mHolder.txtDetail.SetMaxLines(3);
mHolder.txtDetail.SetTextColor(Color.Black);
}
if (mHolder.txtCategory != null)
{
mHolder.txtCategory.Text = mData.NewsSourceTitle;
mHolder.txtCategory.SetTextColor(Color.White);
mHolder.txtCategory.SetBackgroundColor(Color.ParseColor(mData.Color));
}
if (!string.IsNullOrEmpty(mData.PublishedDate))
{
mHolder.txtDate.Text = DateTime.Parse(mData.PublishedDate).ToString("dd MMMM yyyy", CultureInfo.InvariantCulture);
}
break;
case 2:
mHolder.txtTitle.Text = mData.Title;
if (mHolder.viewColor != null)
{
mHolder.viewColor.SetBackgroundColor(Color.ParseColor(mData.Color));
}
if (!string.IsNullOrEmpty(mData.PublishedDate))
{
mHolder.txtDate.Text = DateTime.Parse(mData.PublishedDate).ToString("dd MMMM yyyy", CultureInfo.InvariantCulture);
}
break;
}
return rootView;
}
public class MyViewHolder : Java.Lang.Object
{
public TextView txtTitle { get; set;}
public TextView txtDate{ get; set;}
public TextView txtDetail{ get; set;}
public ImageView imgPlaceholderImage { get; set; }
public View viewColor { get; set; }
public TextView txtCategory { get; set; }
}
}
}
但我总是 mHolder.txtTitle 并且其他组件为 null,即使 mHolder 不为 null。我需要根据它们 positions.Is 来膨胀两种不同的布局 我做错了什么?任何帮助表示赞赏。谢谢
首先,您应该 return getItem 覆盖方法中特定位置的项目
public override Java.Lang.Object GetItem(int position)
{
return myList(position);
}
出现您的问题是因为您的代码有时引用 rootView
,有时引用 convertView
。
在这一行中,您在 convertView
上执行 findViewByID()
:
mHolder.txtTitle=convertView.FindViewById<TextView>(Resource.Id.txtTitle);
但是,您从未检查过 convertView
是否为空,如果是则为其分配新的 View
。相反,您创建了一个对 convertView
的新引用,您将其称为 rootView
,检查 that 是否为 null,如果是,则您分配了一个新的 View
到 rootView。因此,rootView
现在是非空的,但 convertView
仍然是。
public override View GetView(int position,View convertView,ViewGroup parent)
{
View rootView=convertView;
//...
if(rootView==null)
{
mHolder=new MyViewHolder();;
switch(item)
{
case 1:
rootView = homeActivity.LayoutInflater.Inflate(Resource.Layout.phone_home_big_row2,null);
mHolder.txtDate=convertView.FindViewById<TextView>(Resource.Id.txtDate);
// ^^^^^^^^^^ convertView can still be null!!!
//...
}
我建议您删除代码中对 rootView
的所有引用,直接使用 convertView
。这就是将它提供给您的方法的原因。