android - ListView 的回收机制是如何工作的

标签 android android-listview android-gridview

所以我之前遇到了这个问题,自然而然地在here上寻求帮助。 . Luksprog 的回答很棒,因为我不知道 ListView 和 GridView 如何通过回收 View 优化自身。因此,根据他的建议,我能够更改将 View 添加到 GridView 的方式。问题是现在我有一些没有意义的东西。这是我的 getView来自我的 BaseAdapter :

public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            convertView = inflater.inflate(R.layout.day_view_item, parent, false);
        }
        Log.d("DayViewActivity", "Position is: "+position);
        ((TextView)convertView.findViewById(R.id.day_hour_side)).setText(array[position]);
        LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);

        //layout.addView(new EventFrame(parent.getContext()));

        TextView create = new TextView(DayViewActivity.this);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics()), 1.0f);
        params.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        params.bottomMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        create.setLayoutParams(params);
        create.setBackgroundColor(Color.BLUE);
        create.setText("Test"); 
        //the following is my original LinearLayout.LayoutParams for correctly setting the TextView Height
        //new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics()), 1.0f)   
        if(position == 0) {
            Log.d("DayViewActivity", "This should only be running when position is 0. The position is: "+position);
            layout.addView(create);
        }

        return convertView;
    }

}

问题是当我滚动时,会发生这种情况,而不是在位置 0...看起来像位置 6 和位置 8,再加上它在位置 8 上放了两个。现在我仍在尝试使用 ListView 和 GridView,所以我这样做不明白为什么会这样。我提出这个问题的主要原因之一是帮助其他可能不了解 ListView 和 GridView 的回收 View 的人,或者不了解这种方式的人 article说得好,ScrapView 机制。

enter image description here

稍后编辑

添加指向 google IO 演讲的链接,这基本上是您了解 ListView 如何工作所需的全部内容。链接已死在评论中。所以 user3427079 非常好,可以更新该链接。 Here这是为了方便访问。

最佳答案

最初,我也不知道 listview 回收和 convertview 使用机制,但经过一整天的研究,我引用了来自 android.amberfog 的图片,我几乎理解了 ListView 的机制。
enter image description here
每当您的 ListView 被适配器填充时,它基本上会显示 的数量行 ListView 可以显示在屏幕上,即使滚动列表,行数也不会增加。这是 android 使用的技巧,以便 listview 更有效、更快速地工作。
现在listview的内幕引用了图片,正如你所看到的,最初listview有7个可见的项目,然后,如果你向上滚动直到项目1不再可见,getView()将这个 View (即item1)传递给回收商,你可以使用

System.out.println("getview:"+position+" "+convertView);
在你的里面
public View getView(final int position, View convertView, ViewGroup parent)
{
    System.out.println("getview:"+position+" "+convertView);
    ViewHolder holder;
    View row=convertView;
    if(row==null)
    {
        LayoutInflater inflater=((Activity)context).getLayoutInflater();
        row=inflater.inflate(layoutResourceId, parent,false);
        
        holder=new PakistaniDrama();
        holder.tvDramaName=(TextView)row.findViewById(R.id.dramaName);
        holder.cbCheck=(CheckBox)row.findViewById(R.id.checkBox);
        
        row.setTag(holder);
        
    }
    else
    {
        holder=(PakistaniDrama)row.getTag();
    }
            holder.tvDramaName.setText(dramaList.get(position).getDramaName());
    holder.cbCheck.setChecked(checks.get(position));
            return row;
    }
您会在 logcat 中注意到,最初,所有可见行的 convertview 为 null,因为最初回收器中没有 View (即项目),因此您的 getView() 为每个可见项目创建了一个新 View ,但是当您向上滚动并且项目 1 移出屏幕时,它将被发送到 回收商以其当前状态(例如 TextView 'text' 或在我的情况下,如果选中复选框,它将与 View 关联并存储在回收器中)。
现在,当您向上/向下滚动时,您的 ListView 不会创建新 View ,它将使用回收器中的 View 。在您的 Logcat 您会注意到“convertView”不为空,这是因为您的新项目 8 将使用 convertview 绘制,即,基本上它从回收站获取项目 1 View 并将项目 8 充气到其位置,您可以在我的代码。如果您有一个复选框并且您在位置 0 处选中它(假设 item1 有一个复选框并且您选中了它),那么当您向下滚动时,您将看到 item 8 复选框已被选中,这就是 listview 重新使用相同 View 的原因,由于性能优化,不会为您创建新的。
重要事项
1 .永远不要设置 layout_heightlayout_width您的 ListView 到 wrap_contentgetView()将强制您的适配器获取一些子项来测量要在 ListView 中绘制的 View 的高度,并且可能导致一些意外行为,例如即使列表未滚动也返回 convertview。始终使用 match_parent或固定宽度/高度。
2 .如果您想在 ListView 和问题之后使用一些布局或 View ,如果我设置了 layout_heightfill_parent ListView 之后的 View 在屏幕向下时不会显示,因此最好将您的 ListView 放在布局中。例如线性布局并根据您的要求设置该布局的高度和宽度并制作 高度 宽度 你的 ListView 的属性到你的布局(就像你的布局宽度是 320 和高度是 280)那么你的 ListView 应该有相同的 高度 宽度 .这将告诉 getView() 要呈现的 View 的确切高度和宽度,并且 getView() 不会一次又一次地调用一些随机行,并且其他问题,例如在滚动之前返回转换 View 也不会发生,我有测试这就是我自己,除非我的 listview 在 lineaLayout 内,否则它也有问题,例如重复 View 调用和将 View 转换为,将 Listview 放在 LinearLayout 中对我来说就像魔术一样。(不知道为什么)
01-01 14:49:36.606: I/System.out(13871): getview 0 null
01-01 14:49:36.636: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.636: I/System.out(13871): getview 1 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 2 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 3 android.widget.RelativeLayout@406082c0
01-01 14:49:36.656: I/System.out(13871): getview 4 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 5 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.696: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.706: I/System.out(13871): getview 1 null
01-01 14:49:36.736: I/System.out(13871): getview 2 null
01-01 14:49:36.756: I/System.out(13871): getview 3 null
01-01 14:49:36.776: I/System.out(13871): getview 4 null
但现在它解决了,我知道,我不太擅长解释,但因为我花了一整天的时间来理解所以我认为其他像我这样的初学者可以从我的经验中得到帮助,我希望现在你们会有一点理解的 ListView 框架它是如何工作的,因为它非常困惑和棘手,所以初学者在理解它时发现了太多问题

关于android - ListView 的回收机制是如何工作的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11945563/

相关文章:

java - 无法通过资源 ID 检索值

android - 将 res 文件夹中的图像设置为 android 中的 ImageView 时出现意外行为

java - ListItem焦点改变

android - 将 JSONarray 转换为 ArrayList

java - Android:我们可以为Grid-view item 一次设置多个标签吗?

android - Google 的 Vision API 示例 Face Tracker Camera 权限

android - 转到主屏幕而不是上一个 Activity

android - 为什么 Android 不让您知道 ListView 的滚动 y 位置?

android - 单击另一个单元格时如何更改 GridView 单元格的图像?

带有内部边框的 Android GridView