autocompleteTextViewArrayAdapterが更新された場合でも結果が表示されません
-
28-09-2019 - |
質問
AutoCompleTeTextView(ACTV)を取得して、ネットワークリソースから得ている結果を表示しようとしています。私は完了トレシードを2に設定しましたが、キャラクターに入るとリクエストが起動されることがわかります。
私が得ている結果は正しいものです。 「CA」と書いて、結果「車」が自動認定として取得されるとしましょう。 Asynctaskから結果を受信し、結果をArrayAdapterに入れるコールバック関数があります。次に、ACTVで.ShowDropDown()を呼び出し、空のドロップダウンが表示されます(通常の要素の半分のサイズ)。次に、最後の文字「R」を入力し、ACTVが「車」を表示すると、ドロップダウンが表示され、結果が突然リストに表示されます。
私が2人の文字を入力した場合(有効な結果を返します)、最後の文字を削除した場合も同じことが起こります。文字が削除されると、「車」が自動補完値として表示されます。
誰かがこの問題を抱えていましたか?アダプターは結果で満たされているように見えますが、結果は次のアクションまで表示されません。また、アダプターに結果を追加した後、.notifydatasetchanged()を実行しようとしましたが、それは必要ありませんか?
解決
あなたのコードを見ることなく、何が起こっているのかを伝えるのは難しいです。しかし、最初に思い浮かぶのは、あなたのネットワーク要求が別のスレッドで起こっていること、したがってあなたの performFiltering()
空の結果を時期尚早に返す可能性があります。その時点で、 publishResults()
空の結果を返していますが、ドロップダウンは空です。その後、Asynctaskは結果を取り戻し、結果をアダプターのリストに追加しますが、何らかの理由でまだ表示されていません。
しかし、あなたはasynctaskの必要性について間違っているかもしれないと思います。フィルターオブジェクトはすでにasynctaskに似たことをしています: performFiltering()
背景スレッドで行われます publishResults()
PerformFiltering()が終了した後、UIスレッドから呼び出されます。したがって、ネットワークリクエストをパフォーマンスフィルタリング()で直接実行し、結果をFilterResultsオブジェクトに設定できます。ネットワークリクエストが遅すぎてUIの問題を引き起こすことを心配する必要はありません。
少し複雑な代替ソリューションですが、それは私がフィルターオブジェクトで行っていることです(パフォーマンスフィルタリングに必要なブロッキング/同期ステップの代わりに非同期コールバックを使用して、背景にAPI呼び出しを行う既存のアーキテクチャのために(既存のアーキテクチャによる) )、クロススレッドモニタリングを実行するためにwait()/notify()を使用して同期オブジェクトを使用することです。そのため、効果はパフォーマンスフィルタリング()でネットワーク要求を直接実行するのと同じですが、実際には複数のスレッドで発生しています。
// 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呼び出しのアーキテクチャが既に整っており、パフォーマンスフィルタリング()で同期結果を取得するためにその動作を変更したくない場合、1つの可能性にすぎません。
他のヒント
ジョーの答えは行く方法だと思います。ただし、使用する必要があると思います CountDownLatch 待機/通知の代わりに。
その理由は、wait/notifyを使用すると、 "wait()"を開始する前にAPIが実際に非常に高速に戻ると、レース条件の危険があります...この場合、Notifyは効果がなく、Wait()は無期限に待機します。 。ラッチを使用すると、コードは次のようになります(ジョーからコピーされ、変更された):
// 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();
}
}
最後に、コメントを投稿するのに十分なクレジットがありません。そうでなければ...