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

时间:2011-11-23 04:39:08

标签: android android-listview android-adapter

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

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

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

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

4 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

嗯,这是可能的。

重写方法getView并添加ArrayAdapter

我作为测试用例做了什么:

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);
    }
}

}

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

    String itemValue = getItem(position);

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

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

答案 3 :(得分:1)

如果您将适配器设置为具有稳定的ID,则应该在调用getView(...)之前阻止为已经可见的视图调用notifyDataSetChanged()。这可以通过覆盖hasStableIds()来完成,以便它返回true,然后确保getItemId(...)的实现实际上返回稳定且唯一的 ID。< / p>

@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;
}