代码之家  ›  专栏  ›  技术社区  ›  Eric Nordvik

即使更新了ArrayAdapter,AutoCompleteTextView也不显示结果

  •  7
  • Eric Nordvik  · 技术社区  · 16 年前

    我正试图让一个autocompletetextview(actv)显示我从网络资源获得的结果。我已经将completion treshold设置为2,并且我可以看到在输入字符时触发了请求。

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

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

    有人有这个问题吗?适配器似乎已填充了结果,但在我执行下一个操作之前不会显示结果。在将结果添加到适配器后,我还尝试运行.notifydatasetchanged(),但这不应该是必需的,或者?

    2 回复  |  直到 10 年前
        1
  •  16
  •   Joe    16 年前

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

    不过,我认为您可能误解了异步任务的必要性。filter对象已经在执行类似于asynctask的操作: 执行筛选() 在后台线程中完成,并且 发布结果() 在performFiltering()完成后,从UI线程调用。因此,您可以直接在performfiltering()中执行网络请求,并将结果设置为filterresults对象,这样就不必担心网络请求太慢而导致用户界面出现问题。

    另一种解决方案是使用sync,它稍微复杂一些,但这是我在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()中获得同步结果而更改该行为,那么上面的代码示例只是一种可能性。

        2
  •  1
  •   Haytham AbuelFutuh    10 年前

    我认为乔的回答是正确的。不过,我认为你应该 CountDownLatch 而不是等待/通知。

    原因是,使用wait/notify,如果您的api在您开始“wait()”之前真的返回得非常快,那么您就有可能遇到竞争条件……在这种情况下,notify将不起作用,wait()将无限期地等待。 使用闩锁,代码将如下所示(从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();
      }
    }
    

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

    推荐文章