Pergunta

Estou tentando obter um AutoCompleteTextView (ACTV) para exibir resultados que estou obtendo de um recurso de rede. Definei o acaso de conclusão para 2 e posso ver que a solicitação foi disparada quando entro nos caracteres.

O resultado que estou obtendo é o correto. Digamos que eu escrevo "CA" e recebo o resultado "carro" como uma conclusão automática. Eu tenho uma função de retorno de chamada que recebe o resultado de uma asyncTask e coloca o resultado no Arrayadapter. Então eu chamo .ShowDropdown () no ACTV e um suspensão vazio é mostrado (metade do tamanho de um elemento normal). Então, se eu entrar na última letra "R" e o ACTV mostra "carro", o menu suspenso é mostrado e o resultado estará de repente na lista.

O mesmo acontece se eu inseri dois caracteres (que retornam um resultado válido) e remove a última letra. Quando a letra é removida, "carro" é mostrado como um valor de conclusão automática.

Alguém já teve esse problema? Parece que o adaptador está preenchido com o resultado, mas o resultado não aparece até a próxima ação que eu faço. Eu também tentei executar .NotifyDataSchanGed () depois de adicionar o resultado ao adaptador, mas isso não deve ser necessário, ou?

Foi útil?

Solução

Sem ver seu código, é difícil dizer o que poderia estar acontecendo. Mas a primeira coisa que vem à mente é que sua solicitação de rede está acontecendo em um tópico diferente e, portanto, seu performFiltering() pode estar retornando um conjunto de resultados vazios prematuramente. Nesse ponto, publishResults() está retornando o resultado vazio e seu menu suspenso está vazio. Mais tarde, sua assínceta receberá seu resultado de volta e você adicionará os resultados à lista do adaptador, mas, por um motivo ou outro, ele ainda não será exibido.

Eu acho que você pode estar enganado com a necessidade de assíncrogem. O objeto de filtro já está fazendo algo semelhante à assíncena: performFiltering() é feito em um tópico de fundo e publishResults() é chamado do thread da interface do usuário, depois que o desempenho do desempenho () é concluído. Assim, você pode fazer sua solicitação de rede diretamente no PerformFiltering () e definir os resultados no objeto FilterResults, e não precisará se preocupar com a solicitação de rede ser muito lenta e causar problemas na sua interface do usuário.

Uma solução alternativa, que é um pouco mais complicada, mas é o que estou fazendo no meu objeto de filtro (devido à arquitetura existente que chama a API em segundo plano, usando um retorno de chamada assíncrono em vez da etapa de bloqueio/síncrono, conforme necessário para o PerformFiltering ( )), é usar um objeto sincronizado com espera ()/notify () para fazer monitoramento de thread cruzado, portanto, o efeito é o mesmo que fazer a solicitação de rede diretamente no PerformFiltering (), mas está realmente acontecendo em vários threads:

// 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();
    }
}

No entanto, acho que você pode achar que a solução mais fácil é apenas fazer sua solicitação de rede de forma síncrona, diretamente no método do performafiltering (). O exemplo de código acima é apenas uma possibilidade, se você já possui a arquitetura para chamadas de API assíncronas/controladas por retorno de chamada, e não deseja alterar esse comportamento para obter resultados síncronos no PerformFiltering ().

Outras dicas

Eu acho que a resposta de Joe é o caminho a percorrer. No entanto, acho que você deveria usar Countdownlatch em vez de esperar/notificar.

O motivo é que, com espera/notificar, você corre o risco de uma condição de corrida se sua API realmente retornar super rápido antes de começar "aguarde ()" ... Nesse caso, o notificar não terá efeito e espere () aguardará indefinidamente . Com a trava, o código ficará assim (copiado de Joe e modificado):

// 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();
  }
}

Por fim, não tenho crédito suficiente para postar um comentário, caso contrário, eu teria ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top