gpt4 book ai didi

java - Android ListView Adapter 错误调用notifyDataSetChanged,Android bug?

转载 作者:太空狗 更新时间:2023-10-29 13:20:21 25 4
gpt4 key购买 nike

在我一直在开发的应用程序中,我有一个自定义类 DeviceListAdapter扩展BaseAdapter传递给我的 ListView .在我的 DeviceListAdapter类,我保留自己的ArrayList<Device>我用它来生成列表的 View View getView(... ) .每当应用程序导致数据发生变化时,我都会在 DeviceListAdapter 中使用自定义方法更新 ArrayList<Device>以反射(reflect)变化。我已经使用调试器和许多打印语句来检查数据是否按照我的预期进行了更改,添加和删除了 Device。指定的对象。但是,每次更改数据后,我也会调用 notifyDataSetChanged() ,但在 UI 上没有任何元素得到更新。在调试器中,我发现在调用 notifyDataSetChanged() 之后, getView(... )方法没有被调用,这解释了为什么 ListView没有被重绘。为了找出原因,我使用调试器的“进入”功能来跟踪程序执行进入 android 框架的位置,因为我已经下载了 SDK 源代码。我的发现非常有趣。执行路径是这样的:

DeviceListAdapter.notifyDataSetChanged()
BaseAdapter.notifyDataSetChanged()
DataSetObservable.notifyChanged()
AbsListView.onInvalidated()

enter image description here enter image description here enter image description here enter image description here

而是调用 onChanged()方法,它跳转轨道并执行 onInvalidated()一旦达到 AbsListView 的方法.最初我认为这是调试器的错误,可能读取了错误的行号,但我重新启动了我的 Android Studio 并完全卸载并重新安装了应用程序,但结果是一样的。谁能告诉我这是否是 Android 框架的合理问题,或者调试器是否不可靠地跟踪我自己的项目文件之外的执行?

更多关于我对 notifyDataSetChanged() 的实现...我创建了本地方法来覆盖 BaseAdapternotifyDataSetChanged()这样我就可以设置一个 boolean 标志 mForceRedraw在我的里面DeviceListAdapter至于我是否应该强制重绘我的列表条目。在getView(... )方法,我通常检查第二个参数,View convertView为 null,如果为 null,则重绘 View ;如果不为 null,则传递 convertView 并返回它。但是,当“mForceRedraw”为真时,我永远不会返回 convertView ,我明确地重绘了 View 。出现的问题是我之前的担心引起的,即getView()在我执行 notifyDataSetChanged() 后没有被调用.

编辑:这是我的 DeviceListAdapter 的代码 fragment :

    /**
* 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;
}
}

最佳答案

您在适配器中并调用通知数据集已更改。理想情况下甚至不需要。因为您正在修改适配器内部使用的数据集。适配器的 getView 方法将每当需要呈现 View 时总是调用。

convertView 方法只是回收 View (而不是数据)。它只是为您提供了一种替代昂贵的 View 膨胀过程的方法。

那么你的代码应该是什么:

public View getView(final int position, View convertView, ViewGroup parent) {
LinearLayout view;
if (convertView == null) //Regenerate the view
{

/* inflate Draws my views */

} else
{
view = (LinearLayout) convertView;

}

//repopulate this view with the data that needs to appear at this position using getItem(position)


return view;
}

关于java - Android ListView Adapter 错误调用notifyDataSetChanged,Android bug?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29806222/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com