【问题标题】:Yet another getView called multiple times另一个 getView 被多次调用
【发布时间】:2012-06-25 08:42:35
【问题描述】:

我的ListView 中的每个项目都包含一个ImageView 和一个TextView,这将填充远程信息。

我获得了ImageView 的 URL,因此我启动了一个 AsyncTask,它会下载图像并使用下载的位图调用 setImageBitmap

这很顺利,但是当创建 ListView 时,getView() 经常被调用。 它调用前 10 行的 getView 大约 7 倍(只有 7 行可见)。 (所以:0、1 等,10、0、1 等)。

然后我可以顺利滚动到第 10 项。但在那之后,对于每个新行,listview 再次调用前 10 个项目的 getView 大约 7 倍。 (这会导致延迟..)

但是当我从AsyncTask 中删除setImageBitmap 时,这一切都不会发生!

可能是什么问题?会不会是某个布局太大,会导致 getViews 又一连串?

这里有一些代码:

<ListView
    android:id="@+id/mylist"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_alignParentBottom="true"
    android:layout_below="@+id/mydivider"
    android:divider="@+color/mycolor"
    android:dividerHeight="2dp"
    android:fadingEdge="none"
    android:fastScrollEnabled="true"
    android:listSelector="@android:color/transparent"
    android:scrollbars="horizontal"
    android:scrollingCache="false"
    android:smoothScrollbar="false" />

异步任务:

public static class MyTask extends AsyncTask<String, Integer, Bitmap> {
    private LruCache<String, Bitmap> mMap;
    private String mUri;
    private int mPosition;
    private ViewHolder mHolder;

    public MyTask (ViewHolder holder, int position, LruCache<String, Bitmap> map) {
        mMap = map;
        mHolder = holder;
        mPosition = position;
    }

    @Override
    protected Bitmap doInBackground(String... url) {
        mUri = url[0];
        return getBitmapFromURL(mUri);
    }

    @Override
    protected void onPostExecute(Bitmap b) {
        if (b != null) {
            mMap.put(mUri, b);
            if (mPosition == mHolder.position) {
                holder.image.setImageBitmap(b);
            }
        }
    };
}

getView()

row = convertView;
ViewHolder holder;
if (row == null) {
    row = vi.inflate(R.layout.mylayout, null);
    holder = new ViewHolder();
    holder.image = (ImageView) row.findViewById(R.id.myimage);
    holder.title = (TextView) row.findViewById(R.id.mytext);
    row.setTag(holder);
} else {
    holder = (ViewHolder) row.getTag();
}

holder.title.setText("text");
holder.image.setImageResource(R.drawable.mydefaulticon);
holder.position = position;
startMyTask(content, holder, position);

更多信息:

创建新视图时,堆栈跟踪显示 getView 是从 ListView.makeAndAddView() 调用的 但在 getViews 的无用连胜中,它来自ListView.measureHeigthOfChildren()

所以当我设置位图时,布局似乎发生了变化......

【问题讨论】:

  • 是的,看起来如此,即使我认为父级应该在添加图像时自行重新布局,因为父级高度也会受到影响..但这是我认为不确定的..

标签: android listview


【解决方案1】:

问题出在 ListView 的布局中。

参数layout_width被设置为wrap_content,当我将其更改为fill_parent时问题消失了......

【讨论】:

  • 谢谢。工作 100%。
  • 也为我工作。我想知道它是否与 listView 的固有大小有关,如果它匹配其父级而不是填充它?更大的 listView 在逻辑上会更频繁地调用 getView(),因为有更多的单独项可用。
  • 在我的情况下,getView 被反复无限地调用一个位置,即使该特定位置没有什么特别之处。我在同一个屏幕上有多种视图类型以及另一种视图类型。问题是我在一个布局中有多个项目,其中一个项目的宽度由 layoutWeight="1" 确定,以便在其他小部件之后占用剩余空间。将其重新排列为固定宽度解决了这个问题。
  • 不敢相信这实际上解决了我的问题。 +1!
  • 难以置信,这行得通。我有一个 ViewPager,每个页面都有一个 ListFragment,并调试了数周,试图弄清楚为什么滑动如此不稳定。一直以来,我所要做的就是将 ListView 的高度设置为match_parent
【解决方案2】:

我推荐你观看这个视频http://www.youtube.com/watch?v=wDBM6wVEO70

基本上android会多次调用getView来计算视图高度和东西,所以你需要在你的异步中实现某种缓存,如果你不使用身份验证,请检查http://code.google.com/p/android-query/

【讨论】:

    【解决方案3】:

    问题是您的 ListView 不知道每个项目是什么。初始化时,ListView 将测量其所有子项并根据此信息绘制自身。您对 AsyncTask 所做的是更改列表中项目的大小,而不是让 ListView 再次完全绘制自己。这会导致您的 ListView 行为异常。

    解决方案:您应该通过在 AsyncTask 的 PostExecute 中使用 notifyDataSetChanged() 通知适配器来更新您的 ListView。这将允许 ListView 使用新信息绘制自己。

    我希望它有效!

    一些有用的链接:

    http://thinkandroid.wordpress.com/2012/06/13/lazy-loading-images-from-urls-to-listviews/

    Lazy load of images in ListView

    【讨论】:

    【解决方案4】:

    我尝试在 ListView 中使用 fill_parent 作为高度,但我无法做到完美,但我如何通过阻止创建 convertViews(如果它已经存在)来尝试它。它在我的方法中运行良好。

            @Override
            public View getView(final int position, View convertView, ViewGroup parent) {
             if (convertView != null)
                return convertView;
             else {
                //your code...
             }
        }
    

    【讨论】:

      【解决方案5】:

      抱歉回复晚了。我在我的画廊小部件适配器中遇到了同样的问题。我使用了通用图像加载器。 Martijn 的 解决方案对我有用。我所要做的就是在图像已完全下载并设置 imageView 时添加 notifyDataSetChanged()

      【讨论】:

        猜你喜欢
        • 2012-02-27
        • 1970-01-01
        • 1970-01-01
        • 2015-09-09
        • 1970-01-01
        • 1970-01-01
        • 2012-11-13
        • 1970-01-01
        • 2014-11-04
        相关资源
        最近更新 更多