Android ListView 在向下滚动时显示不正确的内容,然后在向上滚动时显示正确的内容

Posted

技术标签:

【中文标题】Android ListView 在向下滚动时显示不正确的内容,然后在向上滚动时显示正确的内容【英文标题】:Android ListView show incorrect content when Scrolling Down, then correct content when Scrolling Up 【发布时间】:2019-01-12 09:41:41 【问题描述】:

作为 android Studio 的新手,我目前对同一代码的不同行为感到困惑。如果代码相同,向上或向下滚动时结果如何不同?这可能是一些 Android 视图回收问题吗?

从网络上的 JSON 文件解析数据后,自定义适配器会读取并设置 ListView 内每一行的相应数据。每行有四条信息:1)标题,2)描述,3)图像 URL(通过毕加索显示)和 4)分配给按钮的 setOnClickListener 的外部 URL,通过浏览器意图。

虽然每一行的标题、描述和图像都可以正常工作,但对于分配给 Button 的 setOnClickListener 的 URL,恰好有一个非常奇怪、奇怪且到目前为止(对我而言)莫名其妙的行为:

1) 首次展示ListView时,在浏览器点击Button打开URL时,系统打开的不是该项目的正确URL,而是Array中NEXT项目对应的URL。

2) 如果一个人向下滚动一点,然后再次向上滚动,当点击同一个按钮时(之前会导致错误的 URL),这一次它确实会打开正确的 URL。

在相同的代码中,在相同的运行中,Button 在向下滚动时会显示错误的 URL,然后在向上滚动时会显示正确的 URL。

到目前为止,我的提示是考虑这可能与 Android 的 Recycling Views 功能有关,但我仍然不知道如何纠正这个问题。

我确实在CustomAdapter.java中包含了以下几行代码,希望防止Recycling:

    @Override
public int getViewTypeCount() 
    return getCount();

@Override
public int getItemViewType(int position) 
    return position;

尽管如此,包含或排除上述代码并没有实际区别。

我的CustomAdapter.java的完整代码如下:

   package ca.costari.apps.ge3000;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.Objects;

public class CustomAdapter extends BaseAdapter 

    private Context context;
    private ArrayList<PlayersModel> playersModelArrayList;
    private String clickurl;

    public CustomAdapter(Context context, ArrayList<PlayersModel> playersModelArrayList) 

        this.context = context;
        this.playersModelArrayList = playersModelArrayList;
    

    @Override
    public int getViewTypeCount() 
        return getCount();
    
    @Override
    public int getItemViewType(int position) 
        return position;
    

    @Override
    public int getCount() 
        return playersModelArrayList.size();
    

    @Override
    public Object getItem(int position) 
        return playersModelArrayList.get(position);
    

    @Override
    public long getItemId(int position) 
        return 0;
    

    @SuppressLint("InflateParams")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) 
        ViewHolder holder;

        if (convertView == null) 
            holder = new ViewHolder();
            LayoutInflater inflater = (LayoutInflater) context

                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                convertView = Objects.requireNonNull(inflater).inflate(R.layout.lv_item, null, true);
            

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                holder.procesa_titulo = Objects.requireNonNull(convertView).findViewById(R.id.id_titulo);
            
            holder.procesa_mensajepromo = convertView.findViewById(R.id.id_mensajepromo);
            holder.procesa_imagenurl = convertView.findViewById(R.id.imageViewPromo);

            convertView.setTag(holder);
        else 
            // the getTag returns the viewHolder object set as a tag to the view
            holder = (ViewHolder)convertView.getTag();
        

        clickurl = playersModelArrayList.get(position).getClickURL();
        holder.procesa_clickurl = convertView.findViewById(R.id.id_clickurl);
        holder.procesa_clickurl.setOnClickListener(new View.OnClickListener() 
            public void onClick(View v) 
                AsignaBotonUrl(v, clickurl);
            
        );
        holder.procesa_titulo.setText(playersModelArrayList.get(position).getTitulo());
        holder.procesa_mensajepromo.setText(playersModelArrayList.get(position).getMensajePromo());

        // Picasso to display image from URL
        Picasso.with(holder.procesa_imagenurl.getContext())
                .load(playersModelArrayList.get(position).getImageURL())
                .placeholder(R.drawable.echale_un_ojo_te_interesa)
                .into(holder.procesa_imagenurl);

        return convertView;
    

    private void AsignaBotonUrl(View view, String url) 
        Intent browserIntent = new Intent(
                Intent.ACTION_VIEW,
                Uri.parse(url));
        view.getContext().startActivity(browserIntent);
    

    private class ViewHolder 
        protected TextView procesa_titulo, procesa_mensajepromo;
        protected ImageView  procesa_imagenurl;
        protected Button procesa_clickurl;
    


上面的代码为下面的ListView xml中包含的项目赋值:

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:padding="10dp"
    android:orientation="vertical">

    <LinearLayout
        android:layout_
        android:layout_
        android:background="#fdfdfd"
        android:orientation="vertical"
        android:layout_marginBottom="30dp"
        tools:ignore="UselessParent">

        <TextView
            android:id="@+id/id_titulo"
            android:layout_
            android:layout_
            android:textColor="#2f2f2f"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="20dp"
            android:gravity="center_vertical"
            android:textSize="20sp"
            android:paddingLeft="10dp" />

        <ImageView
            android:layout_
            android:layout_
            android:id="@+id/imageViewPromo"
            android:layout_marginBottom="20dp"
            android:contentDescription="@string/echale_un_ojo" />

        <TextView
            android:id="@+id/id_mensajepromo"
            android:layout_
            android:layout_
            android:textColor="#2f2f2f"
            android:gravity="center_vertical"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:paddingLeft="10dp"
            android:layout_marginBottom="10dp" />

        <Button
            android:id="@+id/id_clickurl"
            android:layout_
            android:layout_
            android:gravity="center"
            android:textSize="24sp"
            android:text="@string/conocer_mas"
            android:drawableRight="@drawable/open_web"
            android:layout_marginBottom="30dp" />

    </LinearLayout>

</LinearLayout>

这是我在 *** 上的第一篇文章,因此请您耐心等待,因为我可能没有正确提出我的问题,如果我可能需要在此处包含更多代码或提供更多代码,请告诉我信息。

非常感谢!!!

【问题讨论】:

嗯,实际上... 是的,它可以工作 非常感谢 Tyler V !!! 【参考方案1】:

clickurl改成最终的局部变量,所以去掉

private String clickurl

只需在 getView 中使用它,这样每个侦听器都有一个唯一的 URL。

final String clickurl = playersModelArrayList.get(position).getClickURL();

按原样,您的 onClickListener 使用 clickurl 的单个实例(保存在 Adapter 类中的实例),因此它始终会使用在上次调用 getView 时设置的任何内容。

【讨论】:

以上是关于Android ListView 在向下滚动时显示不正确的内容,然后在向上滚动时显示正确的内容的主要内容,如果未能解决你的问题,请参考以下文章

过度滚动时显示标题的Android Listview

Android:向上滚动时显示工具栏(向上拖动),向下滚动时隐藏(向下拖动)

Android sqlite数据库-如何在滚动结束时显示列表视图添加 "加载更多项目"。

在 ListView 上向上滚动时显示 ActionBar

向下滚动Angular时显示导航栏

向下滚动时隐藏标题,向上滚动时显示