Utworzyłem przeszukiwalną aktywność. Teraz chcę dodać sugestie wyszukiwania, które są pobierane z usługi internetowej. Chcę uzyskać asynchroniczne sugestie. Zgodnie z Adding Custom Suggestions potrzebuję przesłonić metodę zapytania, wykonać moje wyszukiwanie sugestii, zbudować własne MatrixCursor i zwrócić je. ale to jest problem, moja prośba o otrzymanie sugestii jest asynchroniczna. więc gdy wynik powróci z net it out zakresu metody zapytania.Android: jak uzyskać asynchroniczne sugestie wyszukiwania z internetu?
Odpowiedz
Najbliższy rzeczą znalazłem rozwiązania tego jest użycie ContentProvider i zrobić żądania sieciowe na metodzie operatora (nawet jeśli to sprzeczne z najlepszych praktyk) Query
, w związku z czym można utworzyć MatrixCursor
jak to pokazują here i here.
Wciąż szukam innych opcji, takich jak używanie numeru SyncAdapter
, który wydaje się przytłaczający w celu pokazania sugestii, które nie są używane nigdzie indziej.
Inną opcją, którą wykonałem, aby wykonać to asynchronicznie, jest użycie AutoCompleteTextView, w ten sposób można utworzyć niestandardową kartę, w której można zaimplementować funkcję getFilter
, jak pokazano w this answer.
Tworzenie programu MatrixCursor w jego przykładzie nie rozwiązuje problemu, ponieważ chcę otrzymywać sugestie asynchronicznie z serwera. – toko
@toko zobacz edycję mojej odpowiedzi, dodałem inną opcję, to ta, którą wybrałem na końcu, która nie zablokuje twojego wątku UI podczas pobierania danych z internetu. –
Problem polega na tym, że nie używam AutoCompleteTextView. Używam okna dialogowego interfejsu wyszukiwania: http://developer.android.com/guide/topics/search/search-dialog.html – toko
Wygląda na to, że żądanie dostawcy treści sugestii nie jest uruchamiane w wątku interfejsu użytkownika, tak czy inaczej, zgodnie z tą odpowiedzią: https://stackoverflow.com/a/12895381/621690. Jeśli możesz zmienić swoje żądanie http, możesz go nazwać blokowaniem w metodzie zapytania. Może pomóc w odsłuchaniu przerw lub innych sygnałów (może być niestandardowych), aby zatrzymać niepotrzebne żądania.
Inna opcja - jeśli nie chcesz zmieniać żadnych klas zleceń, które są już asynchroniczne (np. Jeśli używasz Robospice) - powinieneś po prostu zwrócić referencję MatrixCursor i wypełnić ją później. Klasa AbstractCursor implementuje już wzorzec Observer i wysyła powiadomienia w przypadku zmian. Jeśli system wyszukiwania nasłuchuje, powinien obsłużyć wszelkie zmiany w danych. Muszę jeszcze to zaimplementować, więc nie mogę potwierdzić, że zadziała tak ładnie, jak to sobie wyobraziłem. (Spójrz na źródło CursorLoader, aby uzyskać więcej inspiracji.)
I czy w ogóle nie jest to cały punkt kursora? W przeciwnym razie moglibyśmy po prostu zwrócić listę z danymi.
AKTUALIZACJA: Dla mnie, przy użyciu MatrixCursor nie wyszło. Zamiast tego zaimplementowałem dwa inne rozwiązania:
- Używanie AutoCompleteTextField w połączeniu z niestandardową podklasą ArrayAdapter, która sama używa niestandardowej podklasy Filtru. Metoda
Filter#performFiltering()
(którą przesłonię wywołaniem synchronicznym do usługi zdalnej) jest wywoływana asynchronicznie, a wątek interfejsu użytkownika nie jest blokowany. Używanie elementu SearchWidget z funkcją SearchableActivity i niestandardowym ArrayAdapter (bez niestandardowego filtru). Gdy zamiarem wyszukiwania przychodzi, zdalne żądanie jest uruchamiany (Robospice), a kiedy wraca poprzez oddzwonienie wzywam następujące niestandardowy sposób na moim
ArrayAdapter<Tag>
podklasy:public void addTags(List<Tag> items) { if (items != null && items.size() > 0) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { super.setNotifyOnChange(false); for (Tag tag : items) { super.add(tag); } super.notifyDataSetChanged(); } else { super.addAll(items); } } }
Metoda ta dba o wyzwolenie powiadomienia na adapterze, a tym samym na liście wyników wyszukiwania.
Zdecydowanie właściwy pomysł. Próbuję to zrobić dokładnie, ale wygląda na to, że sugestie wyszukiwania Androida nie nasłuchują zmian kursora. :/W szczególności nazywam 'ContentResolver.notifyChange()', ale nie widzę tego "[SuggestionAdapter"] Androida (https://android.googlesource.com/platform/frameworks/base/+/jb- release/core/java/android/widget/SuggestionsAdapter.java) wywołuje 'registerContentObserver()'. Jakieś pomysły? Czy brakuje mi czegoś? – ryan
Brzmiało to jak dobry pomysł, ale nie wyszło (przynajmniej nie dla mnie). Zaktualizowałem moją odpowiedź za pomocą moich obecnych rozwiązań. – Risadinha
dzięki za aktualizację! te obecne rozwiązania mają sens w przypadku wyników wyszukiwania. Nadal szukam sposobu aktualizacji [search_suggestions_] (http://developer.android.com/guide/topics/search/adding-custom-suggestions.html) po ich zwróceniu. podejrzewam, że może nie być drogi ... ale jeśli znasz jedną, proszę daj nam znać! – ryan
Oto przykład SearchView sugestie pochodzące z usługi sieciowej (użyłem modernizowanych):
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_search_activity, menu);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.search));
final CursorAdapter suggestionAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
null,
new String[]{SearchManager.SUGGEST_COLUMN_TEXT_1},
new int[]{android.R.id.text1},
0);
final List<String> suggestions = new ArrayList<>();
searchView.setSuggestionsAdapter(suggestionAdapter);
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
@Override
public boolean onSuggestionSelect(int position) {
return false;
}
@Override
public boolean onSuggestionClick(int position) {
searchView.setQuery(suggestions.get(position), false);
searchView.clearFocus();
doSearch(suggestions.get(position));
return true;
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
MyApp.autocompleteService.search(newText, new Callback<Autocomplete>() {
@Override
public void success(Autocomplete autocomplete, Response response) {
suggestions.clear();
suggestions.addAll(autocomplete.suggestions);
String[] columns = {
BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_INTENT_DATA
};
MatrixCursor cursor = new MatrixCursor(columns);
for (int i = 0; i < autocomplete.suggestions.size(); i++) {
String[] tmp = {Integer.toString(i), autocomplete.suggestions.get(i), autocomplete.suggestions.get(i)};
cursor.addRow(tmp);
}
suggestionAdapter.swapCursor(cursor);
}
@Override
public void failure(RetrofitError error) {
Toast.makeText(SearchFoodActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
Log.w("autocompleteService", error.getMessage());
}
});
return false;
}
});
return true;
}
Czy możesz lepiej wyjaśnić swoją implementację? Na przykład, jak działa metoda 'doSearch (suggestions.get (position))? Podziękować –
przez wyszukiwarki sugestią znaczy AutoCompleteTextView ?? –
Nie. Używam okna wyszukiwania Androida. jak opisano w dokumentacji: "Korzystając z okna dialogowego wyszukiwania Androida lub widżetu wyszukiwania, możesz podać niestandardowe sugestie wyszukiwania, które są tworzone na podstawie danych w Twojej aplikacji." co próbuję zrobić, to uzyskać te sugestie z serwera, a nie z DB. – toko