【发布时间】:2012-01-05 15:49:10
【问题描述】:
我在自定义实现 Android 的 ArrayAdapter 时遇到了一个奇怪的问题。为了提供一些背景知识,我正在尝试更新 ListView 的内容,同时保留当前滚动位置。
我有一个服务,它执行一个线程来更新 ListView 中显示的数据。该数据存储在 ArrayList 中,并且该 ArrayList 用于为 ListView 生成一些自定义 ArrayAdapter。当 ListView 中的项目被按下(添加或删除项目)时,适配器也会更新。每次有任何类型的更改时,我都会创建新的适配器,然后将这个新的适配器设置为 ListView。这有效,但导致 ListView 每次都滚动到顶部。鉴于我的应用程序的性质,这是不可取的。 ListView 中的当前滚动位置必须在更新之间保持。
我没有创建新的适配器,而是开始使用适配器的 clear() 方法清除需要更新的适配器,然后使用适配器的 add() 方法重建适配器的项目。这两种方法都在适配器上调用。适配器都在其构造函数中设置为 notifyDataOnChange,因此我不必每次都手动调用 notiftyDatasetChanged()(尽管考虑到我的问题,我尝试手动调用它也无济于事)。
这是我的自定义适配器的样子:
public class RealmAdapter extends ArrayAdapter<Realm>
{
Context c;
public RealmAdapter(Context context, int resource, int textViewResourceId)
{
super(context, resource, textViewResourceId);
setNotifyOnChange(true);
c = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
...
}
...
}
长话短说,这是我的问题。当我在适配器上调用 clear() 时,适配器没有被清除。
这是我的线程中 onPostExecute 中的一个 sn-p,它进行更新。我一定要把它放在这里,所以它会在 UI 线程上更新。我还在我的 UI 活动中以私有方法复制了这个确切的代码。此代码在任何地方都不起作用:
appState.favoriteAdapter.clear();
Log.d(LOG_TAG, "COUNT: " + appState.favoriteAdapter.getCount());
for(Realm r : appState.favorites) {
appState.favoriteAdapter.add(r);
}
Log.d(LOG_TAG, "COUNT: " + appState.favoriteAdapter.getCount());
例如,如果上面的适配器中有 3 个项目,则在 clear() 之后立即调用 getCount() 将返回 3 而不是 0。同样,如果 appState.favorites ArrayList 中只有 2 个项目,循环之后的 getCount() 仍然返回 3,而不是 2。因为适配器没有响应任何这些调用,所以无法以任何方式更新。如果有帮助,我可以稍后发布 Logcat,但不会显示任何例外或任何有用的内容。
在我绞尽脑汁数小时后,我似乎遇到的问题是适配器没有响应对任何改变它的方法的调用。我尝试将一个空的 ArrayList 传递给适配器的 super() 调用,但这没有帮助。我是否遗漏了某些东西或错误地使用了 ArrayAdapter?我已经搜索了所有内容,并且已经检查了很多常见问题,例如修改底层数组并期望它更新,不调用(或在我的适配器的外壳设置中)notifyDatasetChanged(),以及使用不受支持的对底层集合的操作。
FavoriteAdapter 的声明非常简单,包含在我的 Application 类中:
public RealmAdapter favoriteAdapter;
这里是上面对 favoriteAdapter 的初始化:
if(appState.favoriteAdapter == null) {
appState.favoriteAdapter = new RealmAdapter(c, R.layout.list_item, R.layout.realm_entry, appState.favorites);
}
else {
appState.favoriteAdapter.clear();
Log.d(LOG_TAG, "COUNT: " + appState.favoriteAdapter.getCount());
for(Realm r : appState.favorites) {
appState.favoriteAdapter.add(r);
}
Log.d(LOG_TAG, "COUNT: " + appState.favoriteAdapter.getCount());
}
以上代码在我的 UI 线程和下载刷新数据的线程中。
在过滤器上方的代码下方放置:
if(appState.favoriteAdapter != null && RealmSelector.realmFilter != null) appState.favoriteAdapter.getFilter().filter(RealmSelector.realmFilter.getText().toString());
过滤器会影响清除列表吗?逻辑会决定不...
【问题讨论】:
-
看来您使用正确。我查看了 ArrayList 的代码,它看起来非常简单。你在适配器上使用某种过滤吗? (这会使事情变得更复杂一些)。你也可以发布你的适配器的初始化和 appState.favoriteAdapter 的声明吗?
-
当然。声明非常简单,包含在我的 Application 类中: public RealmAdapter favoriteAdapter;实际初始化发生在 UI 活动或线程中,具体取决于哪个线程首先访问适配器。它实际上是我之前发布的代码的扩展: if(appState.favoriteAdapter == null) { appState.favoriteAdapter = new RealmAdapter(c, R.layout.list_item, R.layout.realm_entry, appState.favorites);我确实有一个过滤器,我也会发布它。由于 cmets 的格式很奇怪,我也将编辑我的原始帖子。
-
有人有什么想法吗?我仍然不知所措...
-
过滤器的好提示...也许我对过滤器的理解不正确,但我不太明白过滤器如何干扰从 ArrayAdapter 添加或删除项目。我认为过滤器应该过滤已经存在的内容,而不是干扰项目的添加和删除。
标签: android android-listview android-arrayadapter