Подтвердить что ты не робот

Добавить элемент в ListView без перезагрузки

Мне интересно, есть ли способ добавить элемент в ListView, не вызывая перезагрузки всего списка.

У меня есть адаптер ListView, полученный из BaseAdapter, и когда базовая модель получает добавленный новый элемент, он вызывает notifyDataSetChanged(), который запускает перезагрузку ListView.

Элементы в списке имеют изображения, которые динамически загружаются в соответствии с содержимым элемента. Проблема заключается в том, что, когда getView() вызывается во время перезагрузки, параметр convertView, переданный для повторного использования, предшествует другой позиции, поэтому изображения также необходимо перезагрузить, что вызывает довольно уродливое мигание.

Итак, есть способ не перезагрузить весь список, если я добавлю только элемент в конце (и это будет единственный способ добавления новых элементов)? Или, по крайней мере, каким-то образом повторно использовать ячейки для того же положения, если это возможно, чтобы избежать дорогостоящей перезагрузки изображения?

4b9b3361

Ответ 1

Нет, он не может быть в андроиде, что вы можете добавить элемент без обновления списка, потому что, когда вы добавляете элемент, он меняет высоту списка. Посмотрите ниже ссылку, 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

Ответ 2

сделайте это вместо вызова notifyDataSetChanged():

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

Ответ 3

Ну, это возможно.

Переопределить методы getView и добавить ArrayAdapter

Что я сделал, например, как 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);
    }
}

}

В первый раз он загружает все элементы, и изображения загружаются динамически с помощью потока Async. Следующая часть кода в методе getView предотвращает полное обновление списка, поэтому предотвращение мигания изображений:

    String itemValue = getItem(position);

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

ArrayAdapter снова войдет в список, когда новый элемент будет добавлен в список. Просто проверьте, является ли элемент в текущей позиции вновь добавленным элементом. Если нет, верните преобразование, которое является старым, или загрузите элемент и верните пользовательский вид.

Ответ 4

Если вы установили, что ваш адаптер имеет стабильные идентификаторы, он должен запретить вызов getView(...) для представлений, которые уже были видны до вызова notifyDataSetChanged(). Это можно сделать, переопределив hasStableIds(), чтобы он возвращал true, а затем убедился, что ваша реализация getItemId(...) фактически возвращает стабильный и уникальный идентификатор.

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