Android 列表适配器不更新新项目
目前,我有一个ListView,它实现了无休止的列表加载,例如,它将加载X个项目,然后当用户滚动到底部时,它会执行一个AsyncTask调用来加载更多项目,然后将它们加载到列表中并更新它。目前,这一切都在起作用,但问题是,为了让它发挥作用,它必须非常低效地完成,以至于随着列表变长,加载新项目所需的时间也会变长,因为每次都会替换整个列表,这显然是不可取的。以下是我当前如何在AsyncTask获得成功响应后从中更新列表:Android 列表适配器不更新新项目,android,listview,listadapter,Android,Listview,Listadapter,目前,我有一个ListView,它实现了无休止的列表加载,例如,它将加载X个项目,然后当用户滚动到底部时,它会执行一个AsyncTask调用来加载更多项目,然后将它们加载到列表中并更新它。目前,这一切都在起作用,但问题是,为了让它发挥作用,它必须非常低效地完成,以至于随着列表变长,加载新项目所需的时间也会变长,因为每次都会替换整个列表,这显然是不可取的。以下是我当前如何在AsyncTask获得成功响应后从中更新列表: //this first line is what makes the loa
//this first line is what makes the loading so slow, but without it the list returns an empty set when calling notifyDataSetChanged() on the ListAdapter
TopPostFragment.postList = new ArrayList<Post>(TopPostFragment.postList);
TopPostFragment.postList.addAll(result); //result is the new items that were received from the AsyncTask
TopPostFragment.updateList();
我觉得这个问题可能源于我在listAdapter中如何处理它,下面是我在listAdapter中如何处理它的构造函数:
List<Post> postList = null;
public PostListAdapter(Context context, int layoutResourceId, List<Post> list, int whichList, int currentFeedID) {
super(context, layoutResourceId, list);
postList = list;
}
我已经从这里的所有代码中删除了与问题无关的行。如果我将列表复制到一个全新的列表中,列表只会更新,那么我错在哪里呢?如果看不到代码的更多部分,可能很难找出确切的问题。但作为我的一个工作实现示例,您可以查看它是如何工作的 不过,一般来说,根据经验,我从不在适配器中初始化要设置为任何其他列表的列表。相反,我总是使用.add或.addAll或.remove或.clear等来确保对原始列表的引用不会丢失,并且您始终拥有适配器和listview所具有的相同列表的句柄 因此,在代码中进行搜索,并确保适配器中的列表已初始化一次,并且仅对其进行操作,并且从不将=设置为任何其他列表
public class ItemAdapter extends BaseAdapter
{
private final static int VIEWTYPE_PIC = 1;
private final static int VIEWTYPE_NOPIC = 0;
private List<Item> items;
LayoutInflater layoutInflator;
ActivityMain activity;
public ItemAdapter(List<Item> items, LayoutInflater layoutInflator, ActivityMain activity)
{
super();
this.items = new ArrayList<Item>();
updateItemList(items);
this.layoutInflator = layoutInflator;
this.activity = activity;
}
public void updateItemList(List<Item> updatedItems)
{
if (updatedItems != null && updatedItems.size() > 0)
{
// FIND ALL THE DUPLICATES AND UPDATE IF NESSICARY
List<Item> nonDuplicateItems = new ArrayList<Item>();
for (Item newItem : updatedItems)
{
boolean isDuplicate = false;
for (Item oldItem : items)
{
if (oldItem.getId().equals(newItem.getId()))
{
// IF IT IS A DUPLICATE, UPDATE THE EXISTING ONE
oldItem.update(newItem);
isDuplicate = true;
break;
}
}
// IF IT IS NOT A DUPLICATE, ADD IT TO THE NON-DUPLICATE LIST
if (isDuplicate == false)
{
nonDuplicateItems.add(newItem);
}
}
// MERGE
nonDuplicateItems.addAll(items);
// SORT
Collections.sort(nonDuplicateItems, new Item.ItemOrderComparator());
// CLEAR
this.items.clear();
// ADD BACK IN
this.items.addAll(nonDuplicateItems);
// REFRESH
notifyDataSetChanged();
}
}
public void removeItem(Item item)
{
items.remove(item);
notifyDataSetChanged();
}
@Override
public int getCount()
{
if (items == null)
return 0;
else
return items.size();
}
@Override
public Item getItem(int position)
{
if (items == null || position > getCount())
return null;
else
return items.get(position);
}
@Override
public long getItemId(int position)
{
return getItem(position).hashCode();
}
@Override
public int getItemViewType(int position)
{
Item item = getItem(position);
if (item.getPhotoURL() != null && URLUtil.isValidUrl(item.getPhotoURL()) == true)
{
return VIEWTYPE_PIC;
}
return VIEWTYPE_NOPIC;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ItemHolder itemHolder;
if (convertView == null)
{
if (getItemViewType(position) == VIEWTYPE_PIC)
{
convertView = layoutInflator.inflate(R.layout.item_pic, null);
} else
{
convertView = layoutInflator.inflate(R.layout.item, null);
}
// THIS CONSTRUCTOR ALSO CALLS REFRESH ON THE HOLDER FOR US
itemHolder = new ItemHolder(convertView, position);
convertView.setTag(itemHolder);
} else
{
itemHolder = ((ItemHolder) convertView.getTag());
itemHolder.refreshHolder(position);
}
return convertView;
}
@Override
public int getViewTypeCount()
{
return 2;
}
@Override
public boolean hasStableIds()
{
return false;
}
@Override
public boolean isEmpty()
{
return (getCount() < 1);
}
@Override
public boolean areAllItemsEnabled()
{
return true;
}
@Override
public boolean isEnabled(int position)
{
return true;
}
}
非常有趣!我来试一试,你有没有理由改用BaseAdapter,然后调用一个空的super?这两件事中的任何一件可能是我的问题吗?super是出于习惯,我认为它会被插入到编译器中或由编译器假定,无论它是否可能是错误的。我之所以使用BaseAdapter,是因为在本例中,我使用了两种不同的视图类型,并且是因为万一需要更改某些内容,这样以后就更容易进行更改。但我这里的要点是,适配器中的项目列表在构造函数中创建了一次,然后再也没有设置过。只有曾经修改过,我在适配器中为它创建了修改方法。到目前为止,这在我所有的应用程序中都非常有效:AggieDev我希望你指的是德克萨斯A&M,因为这是唯一真正的Aggie;Lol但是,关键是您要给ListAdapter的列表,并确保在您给了适配器列表之后,您不会在代码中设置该列表。然而,由于我总是使用BaseAdapter,所以我在ListAdapter本身方面并没有遇到太多问题:Aggie确实意味着德克萨斯a&M!我将试一试并报告这是否解决了问题。查看这两个GIST以获得高效的按需游标:和测试ContentProvider
public class ItemAdapter extends BaseAdapter
{
private final static int VIEWTYPE_PIC = 1;
private final static int VIEWTYPE_NOPIC = 0;
private List<Item> items;
LayoutInflater layoutInflator;
ActivityMain activity;
public ItemAdapter(List<Item> items, LayoutInflater layoutInflator, ActivityMain activity)
{
super();
this.items = new ArrayList<Item>();
updateItemList(items);
this.layoutInflator = layoutInflator;
this.activity = activity;
}
public void updateItemList(List<Item> updatedItems)
{
if (updatedItems != null && updatedItems.size() > 0)
{
// FIND ALL THE DUPLICATES AND UPDATE IF NESSICARY
List<Item> nonDuplicateItems = new ArrayList<Item>();
for (Item newItem : updatedItems)
{
boolean isDuplicate = false;
for (Item oldItem : items)
{
if (oldItem.getId().equals(newItem.getId()))
{
// IF IT IS A DUPLICATE, UPDATE THE EXISTING ONE
oldItem.update(newItem);
isDuplicate = true;
break;
}
}
// IF IT IS NOT A DUPLICATE, ADD IT TO THE NON-DUPLICATE LIST
if (isDuplicate == false)
{
nonDuplicateItems.add(newItem);
}
}
// MERGE
nonDuplicateItems.addAll(items);
// SORT
Collections.sort(nonDuplicateItems, new Item.ItemOrderComparator());
// CLEAR
this.items.clear();
// ADD BACK IN
this.items.addAll(nonDuplicateItems);
// REFRESH
notifyDataSetChanged();
}
}
public void removeItem(Item item)
{
items.remove(item);
notifyDataSetChanged();
}
@Override
public int getCount()
{
if (items == null)
return 0;
else
return items.size();
}
@Override
public Item getItem(int position)
{
if (items == null || position > getCount())
return null;
else
return items.get(position);
}
@Override
public long getItemId(int position)
{
return getItem(position).hashCode();
}
@Override
public int getItemViewType(int position)
{
Item item = getItem(position);
if (item.getPhotoURL() != null && URLUtil.isValidUrl(item.getPhotoURL()) == true)
{
return VIEWTYPE_PIC;
}
return VIEWTYPE_NOPIC;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ItemHolder itemHolder;
if (convertView == null)
{
if (getItemViewType(position) == VIEWTYPE_PIC)
{
convertView = layoutInflator.inflate(R.layout.item_pic, null);
} else
{
convertView = layoutInflator.inflate(R.layout.item, null);
}
// THIS CONSTRUCTOR ALSO CALLS REFRESH ON THE HOLDER FOR US
itemHolder = new ItemHolder(convertView, position);
convertView.setTag(itemHolder);
} else
{
itemHolder = ((ItemHolder) convertView.getTag());
itemHolder.refreshHolder(position);
}
return convertView;
}
@Override
public int getViewTypeCount()
{
return 2;
}
@Override
public boolean hasStableIds()
{
return false;
}
@Override
public boolean isEmpty()
{
return (getCount() < 1);
}
@Override
public boolean areAllItemsEnabled()
{
return true;
}
@Override
public boolean isEnabled(int position)
{
return true;
}
}