Ответ 1
Здесь я отвечаю на свой вопрос с обманом, который я поселился. По-видимому, notifyDataSetChanged()
можно использовать, только если вы добавляете/удаляете элементы. Если вы обновляете информацию о уже отображаемых элементах, вы можете получить видимые элементы, не обновляющие их внешний вид (getView()
не вызывается на вашем адаптере).
Кроме того, вызов invalidateViews()
на ListView
не работает, как рекламируется. Я все еще получаю такое же глючное поведение, когда getView()
не вызывается для обновления экранных элементов.
Сначала я думал, что проблема вызвана частотой, с которой я звонил notifyDataSetChanged()
/invalidateViews()
(очень быстро, из-за обновлений, поступающих из разных источников). Поэтому я попытался использовать дросселирование этих методов, но все же безрезультатно.
Я все еще не уверен на 100%, это ошибка платформы, но тот факт, что мои hackaround работает, кажется, предлагает это. Таким образом, без лишнего шума мой hackaround состоит в расширении ListView
для обновления видимых элементов. Обратите внимание, что это работает, только если вы правильно используете convertView
в своем адаптере и никогда не возвращаете новый View
, когда был отправлен convertView
. По понятным причинам:
public class ProperListView extends ListView {
private static final String TAG = ProperListView.class.getName();
@SuppressWarnings("unused")
public ProperListView(Context context) {
super(context);
}
@SuppressWarnings("unused")
public ProperListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@SuppressWarnings("unused")
public ProperListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
class AdapterDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
super.onChanged();
refreshVisibleViews();
}
@Override
public void onInvalidated() {
super.onInvalidated();
refreshVisibleViews();
}
}
private DataSetObserver mDataSetObserver = new AdapterDataSetObserver();
private Adapter mAdapter;
@Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
mAdapter = adapter;
mAdapter.registerDataSetObserver(mDataSetObserver);
}
void refreshVisibleViews() {
if (mAdapter != null) {
for (int i = getFirstVisiblePosition(); i <= getLastVisiblePosition(); i ++) {
final int dataPosition = i - getHeaderViewsCount();
final int childPosition = i - getFirstVisiblePosition();
if (dataPosition >= 0 && dataPosition < mAdapter.getCount()
&& getChildAt(childPosition) != null) {
Log.v(TAG, "Refreshing view (data=" + dataPosition + ",child=" + childPosition + ")");
mAdapter.getView(dataPosition, getChildAt(childPosition), this);
}
}
}
}
}