将项目添加到 ListView 而不重新加载

发布于 2024-12-18 02:32:34 字数 385 浏览 3 评论 0原文

我想知道是否有一种方法可以将项目添加到 ListView 而不会导致整个列表的重新加载。

我有一个 BaseAdapter 派生的 ListView 适配器,当底层模型添加新元素时,它会调用 notificationDataSetChanged(),这会触发 ListView 重新加载。

列表中的元素具有图像,这些图像根据元素的内容动态加载。问题是,当在重新加载期间调用 getView() 时,为重用而传递的 ConvertView 参数来自之前的不同位置,因此图像也必须重新加载,这会导致相当难看的闪烁。

那么,如果我只在末尾添加一个项目(这将是添加新项目的唯一方法),有没有办法重新加载整个列表?或者如果可能的话,至少以某种方式重复使用同一位置的单元格,以避免昂贵的图像重新加载?

I'm wondering if there's a way to add an item to the ListView without causing the reload of the whole list.

I have a BaseAdapter-derived ListView adapter, and when the underlying model gets a new element added, it calls notifyDataSetChanged(), which triggers the ListView reload.

The elements in the list have images, which are dynamically loaded according to the element's content. Problem is, when getView() is called during the reload, the convertView parameter passed for reuse is from a different position previously, so the images have to be reloaded, too, which causes a rather ugly blinking.

So is there a way to not reload the whole list if I only add an item at the end (and that will be the only way new items are added)? Or at least somehow reuse the cells for the same position, if possible, to avoid the costly image reload?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我喜欢麦丽素 2024-12-25 02:32:34

没有伙伴在android中你不可能在不刷新列表的情况下添加一个项目,因为当你添加一个项目时它会改变列表视图的高度。请参阅下面的链接,Romain Guy在其中说了同样的事情。

http://groups.google.com/group/android-developers/browse_thread/thread/7e54522c37772d04/05ab fd17b59b07f7?lnk=gst&q=how+to+add+list+item+in+listview+without+reload+the+listview+#05abfd17b59b07f7

No buddy its not possible in android that u can add an item without refresh the list because when u add an item it changes the height of list view.See the below link,Romain Guy said the same thing in it.

http://groups.google.com/group/android-developers/browse_thread/thread/7e54522c37772d04/05abfd17b59b07f7?lnk=gst&q=how+to+add+list+item+in+listview+without+reload+the+listview+#05abfd17b59b07f7

月棠 2024-12-25 02:32:34

这样做而不是调用notifyDataSetChanged():

int firstVisiblePosition = getFirstVisiblePosition();
View view = getChildAt(0);
int distFromTop = (view == null) ? 0 : view.getTop();
setSelectionFromTop(firstVisiblePosition, distFromTop);

do this instead of calling notifyDataSetChanged():

int firstVisiblePosition = getFirstVisiblePosition();
View view = getChildAt(0);
int distFromTop = (view == null) ? 0 : view.getTop();
setSelectionFromTop(firstVisiblePosition, distFromTop);
和我恋爱吧 2024-12-25 02:32:34

嗯,这是可能的。

重写 ArrayAdapter 的 getView 和 add 方法

我做了什么,例如测试用例:

public class custom_row extends ArrayAdapter<String> {

String newItem = "";
Boolean doRefresh = true;

public custom_row(Context context, int resource, ArrayList<String> objects) {
    super(context, resource, objects);
}

public custom_row(Context context, int resource, String[] objects) {
    super(context, resource, objects);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    String itemValue = getItem(position);

    if (doRefresh == false && itemValue != newItem) {
        return convertView;
    }

    LayoutInflater inflater = LayoutInflater.from(getContext());

    View customView = inflater.inflate(R.layout.customr_row, parent, false);
    ImageView myImageView = (ImageView) customView.findViewById(R.id.imageView);

    String url = "https://urltoimage/image.jpg";

    (new DownloadImageTask(myImageView)).execute(url);

    TextView myTextView = (TextView) customView.findViewById(R.id.myCustomText);
    myTextView.setText(itemValue);

    return customView;
}

public void addNewItemToList(String item) {
    this.newItem = item;
    this.doRefresh = false;
    add(item);
}

private class DownloadImageTask extends AsyncTask<String, Integer, Bitmap>{
    private ImageView mImageView;

    public DownloadImageTask(ImageView imageView) {
        this.mImageView = imageView;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        URL url = null;
        Bitmap bmp = null;

        try {
            url = new URL(params[0]);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        try {
            InputStream stream = url.openStream();
            bmp = BitmapFactory.decodeStream(stream);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return bmp;
    }

    @Override
    protected void onPostExecute(Bitmap bmp) {
        this.mImageView.setImageBitmap(bmp);
    }
}

}

第一次加载所有项目,并且图像由异步线程动态加载。 getView 方法中的以下代码部分可防止列表完全刷新,从而防止图像闪烁:

    String itemValue = getItem(position);

    if (doRefresh == false && itemValue != newItem) {
        return convertView;
    }

当将新项目添加到列表中时,ArrayAdapter 将再次遍历列表。只需检查当前位置的item是否是新添加的item即可。如果没有,则返回旧视图的convertView,否则加载该项目并返回自定义视图。

Well, it is possible.

Override the methods getView and add of the ArrayAdapter

What i did for example as testcase:

public class custom_row extends ArrayAdapter<String> {

String newItem = "";
Boolean doRefresh = true;

public custom_row(Context context, int resource, ArrayList<String> objects) {
    super(context, resource, objects);
}

public custom_row(Context context, int resource, String[] objects) {
    super(context, resource, objects);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    String itemValue = getItem(position);

    if (doRefresh == false && itemValue != newItem) {
        return convertView;
    }

    LayoutInflater inflater = LayoutInflater.from(getContext());

    View customView = inflater.inflate(R.layout.customr_row, parent, false);
    ImageView myImageView = (ImageView) customView.findViewById(R.id.imageView);

    String url = "https://urltoimage/image.jpg";

    (new DownloadImageTask(myImageView)).execute(url);

    TextView myTextView = (TextView) customView.findViewById(R.id.myCustomText);
    myTextView.setText(itemValue);

    return customView;
}

public void addNewItemToList(String item) {
    this.newItem = item;
    this.doRefresh = false;
    add(item);
}

private class DownloadImageTask extends AsyncTask<String, Integer, Bitmap>{
    private ImageView mImageView;

    public DownloadImageTask(ImageView imageView) {
        this.mImageView = imageView;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        URL url = null;
        Bitmap bmp = null;

        try {
            url = new URL(params[0]);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        try {
            InputStream stream = url.openStream();
            bmp = BitmapFactory.decodeStream(stream);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return bmp;
    }

    @Override
    protected void onPostExecute(Bitmap bmp) {
        this.mImageView.setImageBitmap(bmp);
    }
}

}

The first time it loads all the items and the images are loaded dynamically by the Async thread. The following part of the code in method getView prevents the list from refreshing it completely, so preventing the blinking of the images:

    String itemValue = getItem(position);

    if (doRefresh == false && itemValue != newItem) {
        return convertView;
    }

The ArrayAdapter will go through the list again when a new item is added to the list. Just check whether the item at the current position is the newly added item. If not then return the convertView which is the old view or else load the item and return the custom view.

机场等船 2024-12-25 02:32:34

如果您将适配器设置为具有稳定的 id,那么它应该阻止为调用 notifyDataSetChanged() 之前已经可见的视图调用 getView(...)。这可以通过重写 hasStableIds() 使其返回 true 来完成,然后确保您的 getItemId(...) 实现是实际上返回一个稳定且唯一的 id。

@Override
public long getItemId(int position) {
    //you can use position if you only append items, otherwise you will
    //need to handle the ids on your own and keep them stable and unique
    final long id = position;

    return id;
}

@Override
public final boolean hasStableIds() {
    return true;
}

If you set your adapter to have stable ids then it should prevent getView(...) from being called for the views that were already visible before calling notifyDataSetChanged(). This can be done by overriding hasStableIds() so that it returns true and then making sure that your implementation of getItemId(...) is actually returning a stable and unique id.

@Override
public long getItemId(int position) {
    //you can use position if you only append items, otherwise you will
    //need to handle the ids on your own and keep them stable and unique
    final long id = position;

    return id;
}

@Override
public final boolean hasStableIds() {
    return true;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文