从 JSON 检索数据后 ViewHolder 不再工作
ViewHolder doesn's work anymore after retrieve data from JSON
在我实施 json 之前一切正常。当我单击详细信息按钮(imageView)时,应弹出 dialogFragment。弹出窗口没问题,问题是,它生成了两个或多个 dialogFragment。 implement json 是否影响 viewholder?或者它与 settag gettag 有关?
这是我的代码(我使用了教程中的 api link):
回收器适配器:
public class MyVoteMAPOAdapter : RecyclerView.Adapter
{
public List<string> mImageList;
public List<MyVote_Data> mVoteData;
Activity context;
public event EventHandler<int> ItemClick;
public MyVoteMAPOAdapter (Activity context, List<MyVote_Data> data)
{
this.context = context;
mVoteData = data;
}
public override RecyclerView.ViewHolder OnCreateViewHolder (ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From (parent.Context).Inflate (Resource.Layout.ItemList, parent, false);
ViewHolder vh = new ViewHolder (itemView, OnClick);
itemView.Tag = vh;
return vh;
}
public override void OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
{
//int item = mData[position];
IWindowManager windowManager = context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
ViewHolder vh = holder as ViewHolder;
setImage (holder, position);
//var imageBitmap = GetImageBitmapFromUrl(mVoteData[position].mPosterImage);
vh.IVDetail.SetTag (Resource.Id.ivDetails, position);
//vh.IVPoster.SetImageBitmap (imageBitmap);
vh.IVDetail.SetImageResource (Resource.Drawable.ic_information);
vh.IVVote.SetImageResource (Resource.Drawable.undi_color);
vh.IVPoster.Click += delegate {
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
};
vh.IVVote.Click += delegate {
if(vh.IVVote.Drawable.GetConstantState().Equals(Resource.Drawable.undi_color)){
vh.IVVote.SetImageResource(Resource.Drawable.undi_grey);
}
else {
vh.IVVote.SetImageResource(Resource.Drawable.undi_color);
}
};
//set a tag for the button to the current clicked position
vh.IVDetail.Click += IVDetail_Click;
vh.TVLike.Text = position.ToString();
}
public void IVDetail_Click (object sender, EventArgs e)
{
//retrieve the tag
int position = (int) (((ImageView) sender).GetTag(Resource.Id.ivDetails));
dialogShow (position);
Console.WriteLine ("KELUARRRRRR!~");
}
public void dialogShow(int position)
{
Android.App.FragmentTransaction transaction = context.FragmentManager.BeginTransaction();
//instantiate a fragment
DetailDialogFragment dialogFragment = DetailDialogFragment.newInstance (mVoteData[position].mName, mVoteData[position].mDescription);
dialogFragment.Show (transaction, "dialog_Fragment");
}
//
public async void setImage(RecyclerView.ViewHolder holder, int position)
{
ViewHolder vh = holder as ViewHolder;
string tempImageString = mVoteData[position].mPosterImage;
var imageBMP = GetImageBitmapFromUrl (tempImageString);
//vh.IVPoster.SetImageBitmap (imageBMP);
vh.IVPoster.SetTag (Resource.Id.ivPoster, position);
if (imageBMP.IsCompleted) {
vh.IVPoster.SetImageBitmap (imageBMP.Result);
} else {
vh.IVPoster.SetImageBitmap (await imageBMP);
}
}
//decode string into bitmap
public async static Task<Bitmap> GetImageBitmapFromUrl(string url)
{
Bitmap imageBitmap = null;
try{
if (url != null)
using (var webClient = new WebClient ()) {
var imageBytes = await webClient.DownloadDataTaskAsync (url);
if (imageBytes != null && imageBytes.Length > 0) {
imageBitmap = BitmapFactory.DecodeByteArray (imageBytes, 0, imageBytes.Length);
}
}
}
catch (Exception e){
Console.WriteLine ("Image Exception : {0}", e);
}
return imageBitmap;
}
public override int ItemCount{
get { return mVoteData.Count; }
}
void OnClick (int position)
{
if (ItemClick != null)
ItemClick (this, position);
}
}
public class ViewHolder : RecyclerView.ViewHolder
{
public ImageView IVPoster { get; private set; }
public TextView TVLike { get; private set; }
public ImageView IVDetail { get; private set; }
public ImageView IVVote { get; private set; }
public ViewHolder (View itemView, Action<int> listener) : base(itemView)
{
IVPoster = itemView.FindViewById <ImageView>(Resource.Id.ivPoster);
TVLike = itemView.FindViewById <TextView>(Resource.Id.tvLike);
IVDetail = itemView.FindViewById <ImageView> (Resource.Id.ivDetails);
IVVote = itemView.FindViewById <ImageView> (Resource.Id.ivVote);
itemView.Click += (sender, e) => listener (base.Position);
}
}
}
Child_Data.cs :
public class MyVote_Data
{
public string mPosterImage { get; set; }
public string mName { get; set; }
public string mDescription { get; set; }
public MyVote_Data ()
{
}
public MyVote_Data(string image, string name, string description)
{
mPosterImage = image;
mName = name;
mDescription = description;
}
public List<MyVote_Data> GetVoteData( string jsonString)
{
string tempImage, temptName, tempDescription;
var myVoteData = new List<MyVote_Data> ();
var data = JsonConvert.DeserializeObject <RootObject2> (jsonString);
foreach (var tempData in data.actors)
{
tempImage = tempData.image;
temptName = tempData.name;
tempDescription = tempData.description;
myVoteData.Add (new MyVote_Data(tempImage, temptName, tempDescription));
}
return myVoteData;
}
}
public class Actor
{
public string name { get; set; }
public string description { get; set; }
public string dob { get; set; }
public string country { get; set; }
public string height { get; set; }
public string spouse { get; set; }
public string children { get; set; }
public string image { get; set; }
}
public class RootObject2
{
public List<Actor> actors { get; set; }
}
我发现有一个问题很突出:
vh.IVPoster.Click += delegate {
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
};
每次你重新使用你的viewholder,它仍然包含之前viewholder的内容。你在那里做的是为每个视图持有者添加一个额外的点击事件处理程序。这就是您看到多个对话框片段的原因。
您需要做的是在分配新事件处理程序之前取消注册 vh.IVPoster.Click 事件处理程序。所以我要做的是将您的委托代码重构为实际方法。然后,您可以使用“-=”注销任何先前的事件处理程序,并使用“+=”注册当前的事件处理程序。
更新:
这是我手工完成的,因此您需要付出一些努力来修复所有编译错误,并使用一些基本的故障排除方法使其正常工作。
首先,创建一个名为 OnIVPosterClicked 的新方法:
private void OnIVPosterClicked(object sender, EventArgs e)
{
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
}
然后注册您的事件处理程序而不是使用委托:
vh.IVPoster.Click += OnIVPosterClicked;
要在 ViewHolder 被回收时注销事件处理程序,您必须重写:
public override void OnViewRecycled(Java.Lang.Object holder)
{
//Unregister any View specific event handlers
var viewHolder = holder as ViewHolder;
viewHolder.IVPoster.Click -= OnIVPosterClicked;
base.OnViewRecycled(holder);
}
这就是它的基本要点。如果您盲目地将其复制并粘贴到您的程序中,它可能无法编译,因此您必须修复这些问题。我不确定你为什么要设置标签。使用此模式,应该可以消除跟踪标签的使用。
在我实施 json 之前一切正常。当我单击详细信息按钮(imageView)时,应弹出 dialogFragment。弹出窗口没问题,问题是,它生成了两个或多个 dialogFragment。 implement json 是否影响 viewholder?或者它与 settag gettag 有关?
这是我的代码(我使用了教程中的 api link):
回收器适配器:
public class MyVoteMAPOAdapter : RecyclerView.Adapter
{
public List<string> mImageList;
public List<MyVote_Data> mVoteData;
Activity context;
public event EventHandler<int> ItemClick;
public MyVoteMAPOAdapter (Activity context, List<MyVote_Data> data)
{
this.context = context;
mVoteData = data;
}
public override RecyclerView.ViewHolder OnCreateViewHolder (ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From (parent.Context).Inflate (Resource.Layout.ItemList, parent, false);
ViewHolder vh = new ViewHolder (itemView, OnClick);
itemView.Tag = vh;
return vh;
}
public override void OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
{
//int item = mData[position];
IWindowManager windowManager = context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
ViewHolder vh = holder as ViewHolder;
setImage (holder, position);
//var imageBitmap = GetImageBitmapFromUrl(mVoteData[position].mPosterImage);
vh.IVDetail.SetTag (Resource.Id.ivDetails, position);
//vh.IVPoster.SetImageBitmap (imageBitmap);
vh.IVDetail.SetImageResource (Resource.Drawable.ic_information);
vh.IVVote.SetImageResource (Resource.Drawable.undi_color);
vh.IVPoster.Click += delegate {
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
};
vh.IVVote.Click += delegate {
if(vh.IVVote.Drawable.GetConstantState().Equals(Resource.Drawable.undi_color)){
vh.IVVote.SetImageResource(Resource.Drawable.undi_grey);
}
else {
vh.IVVote.SetImageResource(Resource.Drawable.undi_color);
}
};
//set a tag for the button to the current clicked position
vh.IVDetail.Click += IVDetail_Click;
vh.TVLike.Text = position.ToString();
}
public void IVDetail_Click (object sender, EventArgs e)
{
//retrieve the tag
int position = (int) (((ImageView) sender).GetTag(Resource.Id.ivDetails));
dialogShow (position);
Console.WriteLine ("KELUARRRRRR!~");
}
public void dialogShow(int position)
{
Android.App.FragmentTransaction transaction = context.FragmentManager.BeginTransaction();
//instantiate a fragment
DetailDialogFragment dialogFragment = DetailDialogFragment.newInstance (mVoteData[position].mName, mVoteData[position].mDescription);
dialogFragment.Show (transaction, "dialog_Fragment");
}
//
public async void setImage(RecyclerView.ViewHolder holder, int position)
{
ViewHolder vh = holder as ViewHolder;
string tempImageString = mVoteData[position].mPosterImage;
var imageBMP = GetImageBitmapFromUrl (tempImageString);
//vh.IVPoster.SetImageBitmap (imageBMP);
vh.IVPoster.SetTag (Resource.Id.ivPoster, position);
if (imageBMP.IsCompleted) {
vh.IVPoster.SetImageBitmap (imageBMP.Result);
} else {
vh.IVPoster.SetImageBitmap (await imageBMP);
}
}
//decode string into bitmap
public async static Task<Bitmap> GetImageBitmapFromUrl(string url)
{
Bitmap imageBitmap = null;
try{
if (url != null)
using (var webClient = new WebClient ()) {
var imageBytes = await webClient.DownloadDataTaskAsync (url);
if (imageBytes != null && imageBytes.Length > 0) {
imageBitmap = BitmapFactory.DecodeByteArray (imageBytes, 0, imageBytes.Length);
}
}
}
catch (Exception e){
Console.WriteLine ("Image Exception : {0}", e);
}
return imageBitmap;
}
public override int ItemCount{
get { return mVoteData.Count; }
}
void OnClick (int position)
{
if (ItemClick != null)
ItemClick (this, position);
}
}
public class ViewHolder : RecyclerView.ViewHolder
{
public ImageView IVPoster { get; private set; }
public TextView TVLike { get; private set; }
public ImageView IVDetail { get; private set; }
public ImageView IVVote { get; private set; }
public ViewHolder (View itemView, Action<int> listener) : base(itemView)
{
IVPoster = itemView.FindViewById <ImageView>(Resource.Id.ivPoster);
TVLike = itemView.FindViewById <TextView>(Resource.Id.tvLike);
IVDetail = itemView.FindViewById <ImageView> (Resource.Id.ivDetails);
IVVote = itemView.FindViewById <ImageView> (Resource.Id.ivVote);
itemView.Click += (sender, e) => listener (base.Position);
}
}
}
Child_Data.cs :
public class MyVote_Data
{
public string mPosterImage { get; set; }
public string mName { get; set; }
public string mDescription { get; set; }
public MyVote_Data ()
{
}
public MyVote_Data(string image, string name, string description)
{
mPosterImage = image;
mName = name;
mDescription = description;
}
public List<MyVote_Data> GetVoteData( string jsonString)
{
string tempImage, temptName, tempDescription;
var myVoteData = new List<MyVote_Data> ();
var data = JsonConvert.DeserializeObject <RootObject2> (jsonString);
foreach (var tempData in data.actors)
{
tempImage = tempData.image;
temptName = tempData.name;
tempDescription = tempData.description;
myVoteData.Add (new MyVote_Data(tempImage, temptName, tempDescription));
}
return myVoteData;
}
}
public class Actor
{
public string name { get; set; }
public string description { get; set; }
public string dob { get; set; }
public string country { get; set; }
public string height { get; set; }
public string spouse { get; set; }
public string children { get; set; }
public string image { get; set; }
}
public class RootObject2
{
public List<Actor> actors { get; set; }
}
我发现有一个问题很突出:
vh.IVPoster.Click += delegate {
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
};
每次你重新使用你的viewholder,它仍然包含之前viewholder的内容。你在那里做的是为每个视图持有者添加一个额外的点击事件处理程序。这就是您看到多个对话框片段的原因。
您需要做的是在分配新事件处理程序之前取消注册 vh.IVPoster.Click 事件处理程序。所以我要做的是将您的委托代码重构为实际方法。然后,您可以使用“-=”注销任何先前的事件处理程序,并使用“+=”注册当前的事件处理程序。
更新:
这是我手工完成的,因此您需要付出一些努力来修复所有编译错误,并使用一些基本的故障排除方法使其正常工作。
首先,创建一个名为 OnIVPosterClicked 的新方法:
private void OnIVPosterClicked(object sender, EventArgs e)
{
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
}
然后注册您的事件处理程序而不是使用委托:
vh.IVPoster.Click += OnIVPosterClicked;
要在 ViewHolder 被回收时注销事件处理程序,您必须重写:
public override void OnViewRecycled(Java.Lang.Object holder)
{
//Unregister any View specific event handlers
var viewHolder = holder as ViewHolder;
viewHolder.IVPoster.Click -= OnIVPosterClicked;
base.OnViewRecycled(holder);
}
这就是它的基本要点。如果您盲目地将其复制并粘贴到您的程序中,它可能无法编译,因此您必须修复这些问题。我不确定你为什么要设置标签。使用此模式,应该可以消除跟踪标签的使用。