7

我正在尝试获取 AutoCompleteTextView(ACTV) 来显示我从网络资源获得的结果。我已将完成阈值设置为 2,我可以看到当我输入字符时会触发请求。

我得到的结果是正确的。假设我写“ca”,我得到结果“car”作为自动完成。我有一个回调函数,它接收来自 AsyncTask 的结果并将结果放入 ArrayAdapter。然后我在 ACTV 上调用 .showDropDown() 并显示一个空的下拉列表(正常元素的一半大小)。然后,如果我输入最后一个字母“r”并且 ACTV 显示“car”,则会显示下拉列表,结果会突然出现在列表中。

如果我输入了两个字符(返回有效结果)并删除最后一个字母,也会发生同样的情况。删除字母后,“汽车”显示为自动完成值。

有人遇到过这个问题吗?看起来适配器充满了结果,但直到我执行下一个操作时结果才会显示。在将结果添加到适配器后,我还尝试运行 .notifyDataSetChanged() ,但这不应该是必需的,或者?

4

2 回答 2

16

如果没有看到您的代码,很难判断会发生什么。但首先想到的是您的网络请求发生在不同的线程上,因此您performFiltering()可能会过早地返回一个空结果集。那时,publishResults()正在返回空结果,并且您的下拉列表为空。稍后,您的 AsyncTask 将返回其结果,并将结果添加到适配器的列表中,但由于某种原因,它尚未显示。

不过,我认为您可能误解了对 AsyncTask 的需求。Filter 对象已经在执行类似于 AsyncTask 的操作: performFiltering()在后台线程中完成,并publishResults()在 performFiltering() 完成后从 UI 线程调用。所以你可以直接在 performFiltering() 中做你的网络请求,并将结果设置到 FilterResults 对象中,你不必担心网络请求太慢而导致你的 UI 出现问题。

另一种解决方案,稍微复杂一些,但这是我在我的 Filter 对象中所做的(由于现有架构在后台执行 API 调用,使用异步回调而不是 performFiltering 所需的阻塞/同步步骤( )),就是用一个带wait()/notify()的同步对象来做跨线程监控,所以效果和performFiltering()中直接做网络请求是一样的,但实际上是多线程发生的:

// in Filter class..
protected FilterResults performFiltering(CharSequence constraint) {

    APIResult response = synchronizer.waitForAPI(constraint);
    // ...
}

// callback invoked after the API call finishes:
public void onAPIComplete(APIResult results) {
    synchronizer.notifyAPIDone(results);
}

private class Synchronizer {
    APIResult result;

    synchronized APIResult waitForAPI(CharSequence constraint) {
        someAPIObject.startAsyncNetworkRequest(constraint);
        // At this point, control returns here, and the network request is in-progress in a different thread.
        try {
            // wait() is a Java IPC technique that will block execution until another
            // thread calls the same object's notify() method.
            wait();
            // When we get here, we know that someone else has just called notify()
            // on this object, and therefore this.result should be set.
        } catch(InterruptedException e) { }
        return this.result;
    }

    synchronized void notifyAPIDone(APIResult result) {
        this.result = result;
        // API result is received on a different thread, via the API callback.
        // notify() will wake up the other calling thread, allowing it to continue
        // execution in the performFiltering() method, as usual.
        notify();
    }
}

但是,我认为您可能会发现最简单的解决方案是直接在 performFiltering() 方法中同步执行您的网络请求。上面的代码示例只是一种可能性,如果您已经为异步/回调驱动的 API 调用准备好了架构,并且您不想更改该行为以在 performFiltering() 中获得同步结果。

于 2010-04-25T05:30:33.177 回答
1

我认为乔的答案是要走的路。但是,我认为您应该使用CountDownLatch而不是等待/通知。

原因是,使用等待/通知,如果您的 API 在您开始“wait()”之前实际上返回超快,您将面临竞争条件的风险......在这种情况下,通知不会产生效果,wait() 将无限期等待. 使用 Latch,代码将如下所示(从 Joe 复制并修改):

// in Filter class..
protected FilterResults performFiltering(CharSequence constraint) {
  APIResult response = synchronizer.waitForAPI(constraint);
  // ...
}

// callback invoked after the API call finishes:
public void onAPIComplete(APIResult results) {
  synchronizer.notifyAPIDone(results);
}

private class Synchronizer {
  APIResult result;
  CountDownLatch latch;

  synchronized APIResult waitForAPI(CharSequence constraint) {
      latch = new CountDownLatch(1);
      someAPIObject.startAsyncNetworkRequest(constraint);
      // At this point, control returns here, and the network request is in-progress in a different thread.
      try {
        // Will wait till the count is 0...
        // If the count is already 0, it'll return immediately. 
        latch.await();
        // When we get here, we know that someone else has just called notify()
        // on this object, and therefore this.result should be set.
    } catch(InterruptedException e) { }
    return this.result;
  }

  synchronized void notifyAPIDone(APIResult result) {
    this.result = result;
    // API result is received on a different thread, via the API callback.
    // countDown() will wake up the other calling thread, allowing it to continue
    // execution in the performFiltering() method, as usual.
    latch.countDown();
  }
}

最后,我没有足够的信用发表评论,否则我会......

于 2015-11-16T19:00:01.590 回答