【发布时间】:2015-04-22 18:40:31
【问题描述】:
在我一直在开发的应用程序中,我有一个自定义类 DeviceListAdapter 扩展 BaseAdapter,它会传递给我的 ListView。在我的DeviceListAdapter 类中,我保留了自己的ArrayList<Device>,我用它来生成带有View getView(... ) 的列表视图。每当应用程序导致数据发生更改时,我都会使用DeviceListAdapter 中的自定义方法来更新ArrayList<Device> 以反映更改。我使用调试器和许多打印语句来检查数据是否按照我的预期进行了更改,按照指定添加和删除 Device 对象。但是,在每次更改数据后,我也会调用notifyDataSetChanged(),但在 UI 上没有任何元素得到更新。在调试器中,我发现调用notifyDataSetChanged() 后,getView(... ) 方法没有被调用,这就解释了为什么ListView 没有被重绘。为了找出原因,我使用调试器的“步入”功能来跟踪程序执行进入 android 框架的位置,因为我已经下载了 SDK 源代码。我发现非常有趣。执行路径是这样的:
DeviceListAdapter.notifyDataSetChanged()
BaseAdapter.notifyDataSetChanged()
DataSetObservable.notifyChanged()
AbsListView.onInvalidated()
而不是调用onChanged() 方法,它跳过轨道并在到达AbsListView 时执行onInvalidated() 方法。最初我认为这是调试器错误,可能读取了错误的行号,但我重新启动了我的 Android Studio 并完全卸载并重新安装了应用程序,但结果是一样的。谁能告诉我这是否是 Android 框架的合法问题,或者调试器在我自己的项目文件之外跟踪执行是否不可靠?
更多关于我的notifyDataSetChanged() 实现...我创建了本地方法来覆盖BaseAdapter 的notifyDataSetChanged(),这样我就可以在DeviceListAdapter 内部设置一个布尔标志mForceRedraw 是否我应该强制重绘我的列表条目。在getView(... ) 方法中,我通常检查第二个参数View convertView 是否为空,如果是,则重绘视图,如果不是,则传递convertView 并返回它。但是,当 'mForceRedraw' 为真时,我从不返回 convertView,我明确地重绘视图。出现的问题是我之前的顾虑造成的,就是我执行notifyDataSetChanged()后没有调用getView()。
编辑:这是我的DeviceListAdapter 的代码 sn-p:
/**
* Serves data about current Device data to the mDeviceListView. Manages the dynamic and
* persistent storage of the configured Devices and constructs views of each individual
* list item for placement in the list.
*/
private class DeviceListAdapter extends BaseAdapter {
private boolean mForceRedraw = false;
/**
* Dynamic array that keeps track of all devices currently being managed.
* This is held in memory and is readily accessible so that system calls
* requesting View updates can be satisfied quickly.
*/
private List<Device> mDeviceEntries;
private Context mContext;
public DeviceListAdapter(Context context) {
this.mContext = context;
this.mDeviceEntries = new ArrayList<>();
populateFromStorage();
}
/**
* Inserts the given device into storage and notifies the mDeviceListView of a data update.
* @param newDevice The device to add to memory.
*/
public void put(Device newDevice) {
Preconditions.checkNotNull(newDevice);
boolean flagUpdatedExisting = false;
for (Device device : mDeviceEntries) {
if (newDevice.isVersionOf(device)) {
int index = mDeviceEntries.indexOf(device);
if(index != -1) {
mDeviceEntries.set(index, newDevice);
flagUpdatedExisting = true;
break;
} else {
throw new IllegalStateException();
}
}
//If an existing device was not updated, then this is a new device, add it to the list
if (!flagUpdatedExisting) {
mDeviceEntries.add(newDevice);
}
TECDataAdapter.setDevices(mDeviceEntries);
notifyDataSetChanged();
}
/**
* If the given device exists in storage, delete it and remove it from the mDeviceListView.
* @param device
*/
public void delete(Device device) {
Preconditions.checkNotNull(device);
//Remove device from mDeviceEntries
Iterator iterator = mDeviceEntries.iterator();
while(iterator.hasNext()) {
Device d = (Device) iterator.next();
if(device.isVersionOf(d)) {
iterator.remove();
}
}
TECDataAdapter.setDevices(mDeviceEntries);
notifyDataSetChanged();
}
/**
* Retrieves Device entries from persistent storage and loads them into the dynamic
* array responsible for displaying the entries in the listView.
*/
public void populateFromStorage() {
List<Device> temp = Preconditions.checkNotNull(TECDataAdapter.getDevices());
mDeviceEntries = temp;
notifyDataSetChanged();
}
public int getCount() {
if (mDeviceEntries != null) {
return mDeviceEntries.size();
}
return 0;
}
public Object getItem(int position) {
return mDeviceEntries.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
LinearLayout view;
if (convertView == null || mForceRedraw) //Regenerate the view
{
/* Draws my views */
} else //Reuse the view
{
view = (LinearLayout) convertView;
}
return view;
}
@Override
public void notifyDataSetChanged() {
mForceRedraw = true;
super.notifyDataSetChanged();
mForceRedraw = false;
}
}
【问题讨论】:
-
你能提供你的应用程序代码的sn-p吗?
标签: java android android-listview baseadapter notifydatasetchanged