2012-07-23 16 views
9

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?

+0

przez wyszukiwarki sugestią znaczy AutoCompleteTextView ?? –

+1

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

Odpowiedz

0

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.

+0

Tworzenie programu MatrixCursor w jego przykładzie nie rozwiązuje problemu, ponieważ chcę otrzymywać sugestie asynchronicznie z serwera. – toko

+0

@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. –

+0

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

1

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:

  1. 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.
  2. 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.

+0

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

+0

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

+0

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

0

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; 
} 
+2

Czy możesz lepiej wyjaśnić swoją implementację? Na przykład, jak działa metoda 'doSearch (suggestions.get (position))? Podziękować –