1

如何停止 getView 调用,直到我再次调用 notifyDatasetChanged()?

我的问题:

我有一个在 textchange 上过滤适配器的文本字段。如果我过于频繁地更改文本,我会得到 ArrayIndexOutOfBoundsException,因为 getView 当然仍在访问适配器列表,而辅助过滤操作已经在运行。

所以ATM是这样的:

  1. 在后台过滤 + notifyDatasetChanged
  2. 多次调用 GetView
  3. 在处理下一个过滤器时,由于第一个过滤器,GetView 仍在后台被调用。但是 GetView 由于列表访问(过滤操作更改列表)而获得异常。所以我想停止 GetView 调用,然后开始任何给定的过滤操作。

编辑:

如果我看到过滤器线程处于活动状态,我正在考虑立即从 getview 返回?

编辑:

OK 相关适配器代码:

@Override
    protected FilterResults performFiltering(CharSequence constraint) {
      filterLock.acquireUninterruptibly();

      FilterResults r = new FilterResults();
      List<T> items = null;
      m_Filter = constraint;

      if (constraint == null /* TextUtils.isEmpty(constraint) */) { // AR
        // auskommentiert
        // da
        // ungewünscht
        items = m_AllItems;
      } else {
        items = m_FilteredItems;
        items.clear();

        synchronized (SyncLock) {
          for (T item : m_AllItems) {
            if (DynamicArrayAdapter.this.filter(item, constraint)) {
              items.add(item);
            }
          }
        }
      }

      r.values = items;
      r.count = items.size();

      return r;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {

      m_Items = (List<T>) results.values;

      notifyDataSetChanged();

      filterLock.release();
    }

这是从过滤器扩展而来的过滤器。m_Items 和 m_AllItems 在适配器中使用(第一个包含过滤的,第二个包含未过滤的)。如您所见,它们在 performFiltering() 中没有被修改。filterLock 也是一个大小为 1 的信号量,因此不会同时发生 2 个过滤操作。

编辑2:

另外,在我的 onTextChanged 中,我可以向您保证,我不会以任何方式修改适配器,也不会在从 performFiltering() 调用的 filter() 方法中

4

1 回答 1

0

不是从 UI 线程更改为适配器是导致您出现问题的原因。如果您将所有适配器修改发布到 UI 线程,它就不会发生,因为它会一个接一个地发生。

您可以在不同的线程中进行繁重的处理,但是当您想将更改放在适配器中时,您需要使用 Handler 或Activity.runOnUiThread. 例如:

// Really heavy filtering process

runOnUiThread(new Runnable(){
          public void run(){
               // Change items of Adapter here
               // Now we are notifying that the data has changed.
               mAdapter.notifyDataSetChanged();
          }
    });

看到你的代码后:正如 Luksprog 所说,你不应该直接从其他线程更改列表,而是使用列表的副本。发生的情况是 ListView 接受大小为 X 的列表,但您已经将其更改为大小为 Y 并且 ListView 不知道它。您需要在项目列表的副本上完成工作,完成后,发布到 UI 线程 aRunnable更改适配器中的项目列表并调用notifyDataSetChanged(),这是您不会与 ListView 和您发生冲突适配器。

于 2013-03-26T20:24:16.860 回答