我有一个问题,几个星期以来一直让我悲伤。当我更新到新的Facebook SDK时,我忘记了一段时间,但现在又回到了困扰我的梦想。
我基本上是一个Facebook提要阅读器。它从API调用中获取JSON数据,并使用它来填充ListView。每次自定义适配器调用getView()方法时,它都会检查它是什么类型的“状态”。如果它是“照片”状态,则视图将具有两个图像(配置文件图片和状态更新的图片)。我正在使用nostra13的通用图像加载器在使用持有者类膨胀ImageViews之后加载两个图像以帮助回收视图。这就是我认为我的问题存在的地方。
当我滚动列表时,所有个人资料图片都可以正常运行并且效果很好。但是当我滚动时,状态照片会做一些事情:
1。)全部加载相同的图像(之前我没有遇到过这个问题,但我试图修复其他图片给自己。)
2。)图像会跳跃并消失或出现在不同的视图中。
3.。)如果图像正确加载并且并非所有图像都显示相同的图像,则图像会随着我上下滚动而改变,最终会变成相同的图像。
我会发布我的getView()代码(抱歉它有点长)。
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
try {
jsonObject = getItem(position);
jsonFrom = jsonObject.getJSONObject("from");
postType = jsonObject.getString("type");
posterName = jsonFrom.getString("name");
posterID = jsonFrom.getString("id");
posterPhoto = "http://graph.facebook.com/" + posterID
+ "/picture?type=square";
if (jsonObject.has("message")) {
posterMessage = jsonObject.getString("message");
} else {
posterMessage = jsonObject.getString("story");
}
} catch (JSONException e) {
e.printStackTrace();
}
if (postType.equals("status")) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.status_post_holder,null);
holder = new ViewHolder();
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.posterName = (TextView) convertView.findViewById(R.id.posterName);
holder.posterMessage = (TextView) convertView.findViewById(R.id.posterMessage);
holder.posterProfilePhoto = (ImageView) convertView.findViewById(R.id.posterProfilePic);
if (jsonObject != null) {
holder.posterName.setText(posterName);
if (posterMessage != null) {
holder.posterMessage.setText(posterMessage);
} else {
holder.posterMessage.setText("No message for this post.");
}
profileImageLoader.displayImage(posterPhoto,
holder.posterProfilePhoto);
}
}
else if (postType.equals("photo")) {
if (convertView == null) {
try {
posterImageURL = jsonObject.getString("picture");
} catch (JSONException e) {
e.printStackTrace();
}
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.photo_post_holder, null);
holder = new ViewHolder();
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.posterName = (TextView) convertView.findViewById(R.id.posterName);
holder.posterMessage = (TextView) convertView.findViewById(R.id.posterMessage);
holder.posterProfilePhoto = (ImageView) convertView.findViewById(R.id.posterProfilePic);
holder.posterImage = (ImageView) convertView.findViewById(R.id.posterImage);
if (jsonObject != null) {
holder.posterName.setText(posterName);
if (posterPhoto != null) {
profileImageLoader.displayImage(posterPhoto,holder.posterProfilePhoto);
}
if (posterImageURL != null) {
pictureImageLoader.displayImage(posterImageURL,holder.posterImage);
}
if (posterMessage != null) {
holder.posterMessage.setText(posterMessage);
} else {
holder.posterMessage.setText("No message for this post.");
}
}
}
else if (postType.equals("link")) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.status_post_holder,null);
holder = new ViewHolder();
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.posterName = (TextView) convertView.findViewById(R.id.posterName);
holder.posterMessage = (TextView) convertView.findViewById(R.id.posterMessage);
holder.posterProfilePhoto = (ImageView) convertView.findViewById(R.id.posterProfilePic);
if (jsonObject != null) {
holder.posterName.setText(posterName);
if (posterMessage != null) {
holder.posterMessage.setText(posterMessage);
} else {
holder.posterMessage.setText("No message for this post.");
}
profileImageLoader.displayImage(posterPhoto,holder.posterProfilePhoto);
}
}
else {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.status_post_holder,null);
holder = new ViewHolder();
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.posterName = (TextView) convertView.findViewById(R.id.posterName);
holder.posterMessage = (TextView) convertView.findViewById(R.id.posterMessage);
holder.posterProfilePhoto = (ImageView) convertView.findViewById(R.id.posterProfilePic);
if (jsonObject != null) {
holder.posterName.setText(posterName);
if (posterMessage != null) {
holder.posterMessage.setText(postType);
} else {
holder.posterMessage.setText("No message for this post.");
}
profileImageLoader.displayImage(posterPhoto,holder.posterProfilePhoto);
}
}
return convertView;
}
我确定它与Android回收视图有关并且效率很高,但我无法弄清楚我在哪里犯错误。这个问题仅存在于一个图像视图中,这也很奇怪。任何帮助都会很热。感谢。
更新:我们发现我的JSON解析出错了。您必须使用setTag()来保留特定于该订单项的图片。适配器试图在视图中设置null标记,从而导致NPE。
再次更新:在挖掘更多内容之后,看起来像是ImageView本身提供了一个空值,好像它找不到正确的布局一样。我为不同类型的帖子使用了两种不同的xml布局。所以现在看起来最好的解决方案是使用相同的布局,并根据状态类型有条件地在每个视图中膨胀不同的元素。
答案 0 :(得分:3)
请在使用和处理图像加载器类时具体说明。 如果可能,请不要创建同一类的更多实例。而不是以不同的方式使用相同的实例。
请参阅下面的适配器类,并尝试在您的情况下集成它。这会对你有所帮助。
private class OrderAdapter extends ArrayAdapter<User> {
private ArrayList<User> items;
Activity a;
public ImageLoader imageLoader;
public OrderAdapter(Context context, int textViewResourceId,ArrayList<User> items) {
super(context, textViewResourceId, items);
this.items = items;
// extra
/*if (Utility.model == null) {
Utility.model = new FriendsGetProfilePics();
}
Utility.model.setListener(this);*/
}
/*@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
super.isEmpty();
return false;
}*/
@Override
public View getView(final int position, View convertView,ViewGroup parent) {
ViewHolder holder;
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.add_buddies_row_new, null);
holder = new ViewHolder();
imageLoader = new ImageLoader(NotificationsActivity.this);
//--------------
//---------------------------------------------------------------------
// for head to head
holder.userName = (TextView) v.findViewById(R.id.txtName);
holder.userPic = (ImageView) v.findViewById(R.id.imgUserPic);
holder.userCity = (TextView) v.findViewById(R.id.txtCity);
holder.userState = (TextView) v.findViewById(R.id.txtstate);
holder.userCountry = (TextView) v.findViewById(R.id.txtContry);
//---------------------------------------------------------------------
v.setTag(holder);
}else{
holder=(ViewHolder)v.getTag();
}
final User o = items.get(position);
holder = (ViewHolder) v.getTag();
if (o != null) {
holder.userName.setText(o.getUserName());
holder.userCity.setText(o.getUserCity()+", ");
holder.userState.setText(o.getUserState()+", ");
holder.userCountry.setText(o.getUserCountry());
System.out.println("PIC: "+o.getUserPic());
holder.userPic.setTag(o.getUserPic());
imageLoader.DisplayImage(o.getUserPic(), a, holder.userPic);
}
return v;
}
}
class ViewHolder {
TextView userName ;
TextView userCity;
TextView userState;
TextView userCountry;
ImageView userPic ;
}
评论我的任何想法。
注意:根据您的要求,您必须根据上述代码进行一些更改。
如果您的问题没有解决,请告诉我。
如果您收到空数据,也会发生这种情况,因此请确认获取数据。
答案 1 :(得分:0)
我知道自创建主题以来已经有一段时间了,但是@Wenger的NPE解决方案出现了,因为我在名为v的View成员而不是ViewHolder上使用了findViewById:
holder.userName = (TextView) v.findViewById(R.id.txtName);
工作参考:
holder.userName = (TextView) convertView.findViewById(R.id.txtName);
答案 2 :(得分:0)
我对视图持有者模式和通用图像加载器有同样的问题。
我在调用通用装载程序显示图像之前检查了我的网址,如果网址为空,我没有下载图像只是设置了图像视图背景可绘制我的无图像可绘制。在Listview滚动中,我的列表视图图像是混合的。
然后我试着不检查url是否为null,只是设置了一个无url drawable到通用图像加载器显示图像选项。这解决了我的问题。我不知道这是否是这个问题的公共解决方案,但你可以尝试一下。
答案 3 :(得分:0)
首先,考虑使用视图类型 - getViewTypeCount()
&amp; getItemViewType(int position)
- ListView
不会尊重您的不同观点 - 更多信息:ListView
回收如何运作。
另外,不要在getView()
中解析json - 在你得到它的地方做它。
另外(如上所述),你应该只启动ImageLoader
一次 - 完美的地方是你的应用程序onCreate()。然后,你称之为 - ImageLoader.getInstance().loadSmth()
;
另外,对你的代码格式做一些事情 - 它太糟糕了。作为提示:
final int viewType = getItemViewType(position);
final int layoutResId;
switch (viewType) {
case 0:
layoutResId = R.layout.layout_1;
break;
case 1:
layoutResId = R.layout.layout_2;
break;
default:
layoutResId = R.layout.layout_3;
}
final View view = mInflater.inflate(layoutResId, group, false);
答案 4 :(得分:0)
您可以执行的修补程序很少
你的观看者几乎没用。您必须按照以下方式使用它
for x in range(5):
for y in range(5):
print(arr[x][y])
您应该只声明一次ImageLoader和DisplayImageOptions实例。可能在构造函数中。
ViewHolder viewHolder;
if (view == null) {
viewHolder = new ViewHolder();
viewHolder.image = (ImageView) view.findViewById(R.id.capsule_media_list_item_thumbnail_1);
view.setTag(viewHolder);
}else{
viewHolder = view.getTag(viewHolder);
}