Listview奇怪的滚动行为

时间:2013-12-01 17:59:14

标签: android listview android-listview

我有一个列表视图(聊天)。我得到一些奇怪的行为。它发生在我向上滚动,然后一些项目开始搞乱,当我回到底部时,项目也搞砸了。我唯一能想到的是每次滚动都会调用我的getView几次。有谁知道我怎么能解决这个问题?

我看到这篇文章:Custom ListView adapter, strange ImageView behavior 但是在创建之后,他不会在列表中添加项目。


<?xml version="1.0" encoding="utf-8"?>

<TextView
    android:id="@+id/right_message"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_toLeftOf="@+id/right_profilePic"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="20dp"
    android:autoLink="all"
    />


 <ImageView
     android:id="@+id/left_profilePic"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentBottom="true"
     android:layout_alignParentLeft="true"
     />

 <TextView
     android:id="@+id/left_message"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentBottom="true"
     android:layout_toRightOf="@+id/left_profilePic"
     android:layout_marginLeft="5dp"
     android:layout_marginRight="5dp"
     android:layout_marginTop="20dp"
     android:autoLink="all" 
     />

 <ImageView
     android:id="@+id/right_profilePic"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentBottom="true"
     android:layout_alignParentRight="true" 
     />

 <TextView
     android:id="@+id/left_time"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentTop="true"
     android:layout_marginLeft="70dp"
     android:layout_toRightOf="@+id/left_profilePic"
     android:textColor="@color/Gray" 
     />

 <TextView
     android:id="@+id/right_time"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentTop="true"
     android:layout_marginRight="70dp"
     android:layout_toLeftOf="@+id/right_profilePic"
     android:textColor="@color/Gray" 
     />

 <ImageView
     android:id="@+id/left_image_message"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentBottom="true"
     android:layout_toRightOf="@+id/left_profilePic"
     android:layout_marginLeft="5dp"
     android:layout_marginRight="5dp"
     android:layout_marginTop="20dp"
     />

 <ImageView
     android:id="@+id/right_image_message"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentBottom="true"
     android:layout_toLeftOf="@+id/right_profilePic"
     android:layout_marginLeft="5dp"
     android:layout_marginRight="5dp"
     android:layout_marginTop="20dp"
     />


更新

我必须在聊天中加载图片和谷歌静态地图,我想这对于列表视图来说很重要。

这是getView方法:

   public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
       Log.d("getView", "getview called");
       ViewHolder holder;
       if(convertView==null)
    {
        holder = new ViewHolder();
        convertView = inflater.inflate(R.layout.chat_item, null);

        holder.right_profilePic = (ImageView)     convertView.findViewById(R.id.right_profilePic);
        holder.right_message = (TextView) convertView.findViewById(R.id.right_message);
        holder.left_profilePic = (ImageView) convertView.findViewById(R.id.left_profilePic);
        holder.left_message = (TextView) convertView.findViewById(R.id.left_message);
        holder.right_time = (TextView) convertView.findViewById(R.id.right_time);
        holder.left_time = (TextView) convertView.findViewById(R.id.left_time);
        holder.right_image_message = (ImageView) convertView.findViewById(R.id.right_image_message);
        holder.left_image_message = (ImageView) convertView.findViewById(R.id.left_image_message);


        convertView.setTag(holder);
    }
    else
        holder=(ViewHolder)convertView.getTag();

    ChatItemBean bean = (ChatItemBean) chatItemList.get(position);
    Log.d("holder", bean.getId() + " | " + GlobalData.myId);
    if (bean.getId().equals(GlobalData.myId)) {
        Picasso.with(context).load(bean.getImage()).resize(130, 130).into(holder.right_profilePic);
        if (bean.getType().equals("1")) {
            Picasso.with(context).load(init_link + bean.getMessage()).into(holder.right_image_message);
            holder.right_image_message.setBackgroundResource(R.drawable.chat_background_right);
            //holder.right_image_message.setPadding(0, 0, 0, 20);
        } else if (bean.getType().equals("2")) {
            StringTokenizer tokens = new StringTokenizer(bean.getMessage(), "&");
            String first = tokens.nextToken();
            String second = tokens.nextToken();
            String url = "http://maps.google.com/maps/api/staticmap?center=" + 
                            first + "," + second + "&zoom=15&size=200x200&sensor=false";
            Picasso.with(context).load(url).into(holder.right_image_message);
            holder.right_image_message.setBackgroundResource(R.drawable.chat_background_right);
        } else {
            holder.right_message.setText(bean.getMessage());
            holder.right_message.setBackgroundResource(R.drawable.chat_background_right);
            }
        holder.right_time.setText(bean.getTime());
    } else {
        Picasso.with(context).load(bean.getImage()).resize(130, 130).into(holder.left_profilePic);

        if (bean.getType().equals("1")) { 
            Picasso.with(context).load(init_link + bean.getMessage()).into(holder.left_image_message);
            holder.left_image_message.setBackgroundResource(R.drawable.chat_background_left);
            holder.left_image_message.setPadding(0, 10, 0, 30);

        } else if (bean.getType().equals("2")) {
            StringTokenizer tokens = new StringTokenizer(bean.getMessage(), "&");
            String first = tokens.nextToken();
            String second = tokens.nextToken();
            String url = "http://maps.google.com/maps/api/staticmap?center=" + 
                            first + "," + second + "&zoom=15&size=200x200&sensor=false";
            Picasso.with(context).load(url).into(holder.left_image_message);
            holder.left_image_message.setBackgroundResource(R.drawable.chat_background_left);
        } else {
            holder.left_message.setText(bean.getMessage());
            holder.left_message.setBackgroundResource(R.drawable.chat_background_left);
        }

        holder.left_time.setText(bean.getTime());
    }
    return convertView;
}public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    Log.d("getView", "getview called");
    ViewHolder holder;
    if(convertView==null)
    {
        holder = new ViewHolder();
        convertView = inflater.inflate(R.layout.chat_item, null);

        holder.right_profilePic = (ImageView) convertView.findViewById(R.id.right_profilePic);
        holder.right_message = (TextView) convertView.findViewById(R.id.right_message);
        holder.left_profilePic = (ImageView) convertView.findViewById(R.id.left_profilePic);
        holder.left_message = (TextView) convertView.findViewById(R.id.left_message);
        holder.right_time = (TextView) convertView.findViewById(R.id.right_time);
        holder.left_time = (TextView) convertView.findViewById(R.id.left_time);
        holder.right_image_message = (ImageView) convertView.findViewById(R.id.right_image_message);
        holder.left_image_message = (ImageView) convertView.findViewById(R.id.left_image_message);


        convertView.setTag(holder);
    }
    else
        holder=(ViewHolder)convertView.getTag();

    ChatItemBean bean = (ChatItemBean) chatItemList.get(position);
    Log.d("holder", bean.getId() + " | " + GlobalData.myId);
    if (bean.getId().equals(GlobalData.myId)) {
        Picasso.with(context).load(bean.getImage()).resize(130, 130).into(holder.right_profilePic);
        if (bean.getType().equals("1")) {
            Picasso.with(context).load(init_link + bean.getMessage()).into(holder.right_image_message);
            holder.right_image_message.setBackgroundResource(R.drawable.chat_background_right);
            //holder.right_image_message.setPadding(0, 0, 0, 20);
        } else if (bean.getType().equals("2")) {
            StringTokenizer tokens = new StringTokenizer(bean.getMessage(), "&");
            String first = tokens.nextToken();
            String second = tokens.nextToken();
            String url = "http://maps.google.com/maps/api/staticmap?center=" + 
                            first + "," + second + "&zoom=15&size=200x200&sensor=false";
            Picasso.with(context).load(url).into(holder.right_image_message);
            holder.right_image_message.setBackgroundResource(R.drawable.chat_background_right);
        } else {
            holder.right_message.setText(bean.getMessage());
            holder.right_message.setBackgroundResource(R.drawable.chat_background_right);
            }
        holder.right_time.setText(bean.getTime());
    } else {
        Picasso.with(context).load(bean.getImage()).resize(130, 130).into(holder.left_profilePic);

        if (bean.getType().equals("1")) { 
            Picasso.with(context).load(init_link + bean.getMessage()).into(holder.left_image_message);
            holder.left_image_message.setBackgroundResource(R.drawable.chat_background_left);
            holder.left_image_message.setPadding(0, 10, 0, 30);

        } else if (bean.getType().equals("2")) {
            StringTokenizer tokens = new StringTokenizer(bean.getMessage(), "&");
            String first = tokens.nextToken();
            String second = tokens.nextToken();
            String url = "http://maps.google.com/maps/api/staticmap?center=" + 
                            first + "," + second + "&zoom=15&size=200x200&sensor=false";
            Picasso.with(context).load(url).into(holder.left_image_message);
            holder.left_image_message.setBackgroundResource(R.drawable.chat_background_left);
        } else {
            holder.left_message.setText(bean.getMessage());
            holder.left_message.setBackgroundResource(R.drawable.chat_background_left);
        }

        holder.left_time.setText(bean.getTime());
    }
    return convertView;
}

public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    Log.d("getView", "getview called");
    ViewHolder holder;
    if(convertView==null)
    {
        holder = new ViewHolder();
        convertView = inflater.inflate(R.layout.chat_item, null);

        holder.right_profilePic = (ImageView) convertView.findViewById(R.id.right_profilePic);
        holder.right_message = (TextView) convertView.findViewById(R.id.right_message);
        holder.left_profilePic = (ImageView) convertView.findViewById(R.id.left_profilePic);
        holder.left_message = (TextView) convertView.findViewById(R.id.left_message);
        holder.right_time = (TextView) convertView.findViewById(R.id.right_time);
        holder.left_time = (TextView) convertView.findViewById(R.id.left_time);
        holder.right_image_message = (ImageView) convertView.findViewById(R.id.right_image_message);
        holder.left_image_message = (ImageView) convertView.findViewById(R.id.left_image_message);


        convertView.setTag(holder);
    }
    else
        holder=(ViewHolder)convertView.getTag();

    ChatItemBean bean = (ChatItemBean) chatItemList.get(position);
    Log.d("holder", bean.getId() + " | " + GlobalData.myId);
    if (bean.getId().equals(GlobalData.myId)) {
        Picasso.with(context).load(bean.getImage()).resize(130, 130).into(holder.right_profilePic);
        if (bean.getType().equals("1")) {
            Picasso.with(context).load(init_link + bean.getMessage()).into(holder.right_image_message);
            holder.right_image_message.setBackgroundResource(R.drawable.chat_background_right);
            //holder.right_image_message.setPadding(0, 0, 0, 20);
        } else if (bean.getType().equals("2")) {
            StringTokenizer tokens = new StringTokenizer(bean.getMessage(), "&");
            String first = tokens.nextToken();
            String second = tokens.nextToken();
            String url = "http://maps.google.com/maps/api/staticmap?center=" + 
                            first + "," + second + "&zoom=15&size=200x200&sensor=false";
            Picasso.with(context).load(url).into(holder.right_image_message);
            holder.right_image_message.setBackgroundResource(R.drawable.chat_background_right);
        } else {
            holder.right_message.setText(bean.getMessage());
            holder.right_message.setBackgroundResource(R.drawable.chat_background_right);
            }
        holder.right_time.setText(bean.getTime());
    } else {
        Picasso.with(context).load(bean.getImage()).resize(130, 130).into(holder.left_profilePic);

        if (bean.getType().equals("1")) { 
            Picasso.with(context).load(init_link + bean.getMessage()).into(holder.left_image_message);
            holder.left_image_message.setBackgroundResource(R.drawable.chat_background_left);
            holder.left_image_message.setPadding(0, 10, 0, 30);

        } else if (bean.getType().equals("2")) {
            StringTokenizer tokens = new StringTokenizer(bean.getMessage(), "&");
            String first = tokens.nextToken();
            String second = tokens.nextToken();
            String url = "http://maps.google.com/maps/api/staticmap?center=" + 
                            first + "," + second + "&zoom=15&size=200x200&sensor=false";
            Picasso.with(context).load(url).into(holder.left_image_message);
            holder.left_image_message.setBackgroundResource(R.drawable.chat_background_left);
        } else {
            holder.left_message.setText(bean.getMessage());
            holder.left_message.setBackgroundResource(R.drawable.chat_background_left);
        }

        holder.left_time.setText(bean.getTime());
    }
    return convertView;
}

enter image description here


更新

这里我尝试使用两种不同的布局:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    Log.d("getView", "getview called");
    ViewHolder holder;
    ChatItemBean checkBean = (ChatItemBean) chatItemList.get(position);

    if (checkBean.getId().equals(GlobalData.myId)) {
         if(convertView==null)
         {
             holder = new ViewHolder();
             convertView = inflater.inflate(R.layout.chat_item_right, null);
             holder.right_profilePic = (ImageView) convertView.findViewById(R.id.right_profilePic);
             holder.right_message = (TextView) convertView.findViewById(R.id.right_message);
             holder.right_time = (TextView) convertView.findViewById(R.id.right_time);
             holder.right_image_message = (ImageView) convertView.findViewById(R.id.right_image_message);
             convertView.setTag(holder);
         } else 
             holder=(ViewHolder)convertView.getTag();

         ChatItemBean bean = (ChatItemBean) chatItemList.get(position);
         Log.d("holder", bean.getId() + " | " + GlobalData.myId);

         Picasso.with(context).load(bean.getImage()).resize(130, 130).into(holder.right_profilePic);
        if (bean.getType().equals("1")) {
            Picasso.with(context).load(init_link + bean.getMessage()).into(holder.right_image_message);
            holder.right_image_message.setBackgroundResource(R.drawable.chat_background_right);
            //holder.right_image_message.setPadding(0, 0, 0, 20);
        } else if (bean.getType().equals("2")) {
            StringTokenizer tokens = new StringTokenizer(bean.getMessage(), "&");
            String first = tokens.nextToken();
            String second = tokens.nextToken();
            String url = "http://maps.google.com/maps/api/staticmap?center=" + 
                            first + "," + second + "&zoom=15&size=200x200&sensor=false";
            Picasso.with(context).load(url).into(holder.right_image_message);
            holder.right_image_message.setBackgroundResource(R.drawable.chat_background_right);
        } else {
            holder.right_message.setText(bean.getMessage());
            holder.right_message.setBackgroundResource(R.drawable.chat_background_right);
            }
        holder.right_time.setText(bean.getTime());

    } else {
        if(convertView==null)
        {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.chat_item, null);

            holder.left_profilePic = (ImageView) convertView.findViewById(R.id.left_profilePic);
            holder.left_message = (TextView) convertView.findViewById(R.id.left_message);
            holder.left_time = (TextView) convertView.findViewById(R.id.left_time);
            holder.left_image_message = (ImageView) convertView.findViewById(R.id.left_image_message);

            convertView.setTag(holder);
        }
        else
            holder=(ViewHolder)convertView.getTag();

        ChatItemBean bean = (ChatItemBean) chatItemList.get(position);
        Log.d("holder", bean.getId() + " | " + GlobalData.myId);

            Picasso.with(context).load(bean.getImage()).resize(130, 130).into(holder.left_profilePic);

            if (bean.getType().equals("1")) { 
                Picasso.with(context).load(init_link + bean.getMessage()).into(holder.left_image_message);
                holder.left_image_message.setBackgroundResource(R.drawable.chat_background_left);
                holder.left_image_message.setPadding(0, 10, 0, 30);

            } else if (bean.getType().equals("2")) {
                StringTokenizer tokens = new StringTokenizer(bean.getMessage(), "&");
                String first = tokens.nextToken();
                String second = tokens.nextToken();
                String url = "http://maps.google.com/maps/api/staticmap?center=" + 
                                first + "," + second + "&zoom=15&size=200x200&sensor=false";
                Picasso.with(context).load(url).into(holder.left_image_message);
                holder.left_image_message.setBackgroundResource(R.drawable.chat_background_left);
            } else {
                holder.left_message.setText(bean.getMessage());
                holder.left_message.setBackgroundResource(R.drawable.chat_background_left);
            }

            holder.left_time.setText(bean.getTime());
    }

    return convertView;
}

但是我的应用程序崩溃了,当我滚动一点,就像它试图搞砸的那一刻,我得到的目标不能为空。第124行使用毕加索加载配置文件。

12-01 21:14:40.442: E/AndroidRuntime(21764): java.lang.IllegalArgumentException: Target must not be null.
12-01 21:14:40.442: E/AndroidRuntime(21764):    at com.squareup.picasso.RequestCreator.into(RequestCreator.java:333)
12-01 21:14:40.442: E/AndroidRuntime(21764):    at com.squareup.picasso.RequestCreator.into(RequestCreator.java:319)
12-01 21:14:40.442: E/AndroidRuntime(21764):    at com.petcial.petopen.custom.ChatCustomAdapter.getView(ChatCustomAdapter.java:124)

4 个答案:

答案 0 :(得分:1)

  1. 将Seprate布局文件用于不同类型的列表项 -
  2. 使用两个布局文件最终会丢失一些convertView可重用性能的东西。但是会帮助你拥有可以解决这个烂摊子的清洁用品。确定哪个文件用于哪个项目。

    2。使用一个布局文件。

    可以/(需要付出努力)干净地定义一个文件的布局,以便为所有类型的列表项正确使用它们。使用相对布局并将一个x1放在另一个x2之上。并根据类型简单地在getView中使x1或x2可见或不可见。 确保在getView中没有繁重的操作。其中x1和x2是您的一个项目类型的布局。

    试试这个。但您肯定可以发布您的代码以获得更多帮助。但建议首先尝试清理。

    更新: 转到选项2.使用一个RelativeLayout并在其中添加两个LinearLayout。 一个在另一个之上并在第一个LinearLayout中定义一个项类型,在第二个中定义另一个。 使这些容器(LL)在getView

    中可见或不可见

    希望这个建议有所帮助

答案 1 :(得分:1)

Lars Vogel的

This教程令人惊叹。我强烈推荐使用它。在没有看到您的JAva代码的情况下,我可以说您需要为列表条目提供两种不同的布局XML。一个用于左侧图像,另一个用于右侧图像。然后,在适配器中,为会话的那一部分充气。

这是正确的方法。我认为发生在你身上的是你在回收的ViewGroup中添加了内容,这些内容传递给了getView而没有删除旧的内容,所以你的新东西被添加到旧的东西之上。使用新流程,您需要确保循环视图是正确的“方向”,然后删除旧内容并添加新内容。

以下是我在上面链接的Vogella文章中的部分。

  

getView()方法中,您将扩展基于XML的布局,然后根据此行的Java对象设置各个视图的内容。要扩展XML布局文件,您可以使用系统服务LayoutInflator。可以通过活动或context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)方法调用访问此服务。

     

可以通过顶级视图上的findViewById()方法调用找到布局中的各个元素。

顺便说一句,getView()在滚动期间被多次调用,并且调用的顺序是不可预测的。因此,不要在getView方法中做任何过于密集的事情,否则减速将非常明显。

答案 2 :(得分:0)

这是常见问题,已在StackOverflow中提出过。但是,首先检查一下android工程师RomainGuy所说的getView()方法调用

  

这不是问题,订单绝对没有保证   getView()将被调用多少次。

因此,您可以正确处理re-using the existing views(行布局)。

或者只需在适配器类中添加这行代码。

@Override
public int getViewTypeCount() {

    if (getCount() != 0)
        return getCount();

    return 1;
}

答案 3 :(得分:0)

我有确切的问题,我通过不使用convertView来解决它。

基本上,我所做的是:

public View getView(int position, View convertView, ViewGroup parent) {

    View rowView = inflater.inflate(R.layout.your_layout, parent, false);

    //Do what you intend to do, populate the TextView, or set the ImageViews, but do them with respect to rowView, not convertView.

    ImageView imageView = (ImageView) rowView.findViewById(R.id.my_picture);

    imageView.setImageResources(R.drawable.sample_picture);

    return rowView;

}

无论您使用1个布局还是2个列表项,这都很有用,希望这会有所帮助: - )