7

ネットワーク リソースから取得した結果を表示する AutoCompleteTextView(ACTV) を取得しようとしています。完了しきい値を 2 に設定しました。文字を入力すると、リクエストが発生することがわかります。

私が得ている結果は正しいものです。「ca」と書いて、オートコンプリートとして「car」という結果を得たとしましょう。AsyncTask から結果を受け取り、その結果を ArrayAdapter に入れるコールバック関数があります。次に、ACTV で .showDropDown() を呼び出すと、空のドロップダウンが表示されます (通常の要素の半分のサイズ)。次に、最後の文字「r」を入力してACTVに「car」と表示されると、ドロップダウンが表示され、結果が突然リストに表示されます。

2 文字を入力して (有効な結果が返されます)、最後の文字を削除した場合も同様です。文字が削除されると、オートコンプリート値として「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() で同期結果を取得したくない場合の 1 つの可能性にすぎません。

于 2010-04-25T05:30:33.177 に答える