Search code examples
androidsqlitesearchandroid-contentprovider

Android SearchView: passing data to details acivity


I am following this tutorial to create a search view in my toolbar. What I want is when I click on one of the search result items I want to display its corresponding data in a details activity but I can't seem to make it happen.

This is my code:

MainActivity class:

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_search, menu);

        MenuItem searchItem = menu.findItem(R.id.search);
        SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setOnQueryTextListener(this);

        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(
                new ComponentName(this, SearchableActivity.class)));
        searchView.setIconifiedByDefault(false);

        return true;
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            Toast.makeText(this, "Searching by: "+ query, Toast.LENGTH_SHORT).show();

        } else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
            String uri = intent.getDataString();
            Toast.makeText(this, "Suggestion: "+ uri, Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        // User pressed the search button
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        // User changed the text
        return false;
    }

SearchableActivity class:

public class SearchableActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_searchable);
        TextView txt = (TextView)findViewById(R.id.textView);

        Intent intent = getIntent();
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            txt.setText("Searching by: "+ query);

        } else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
            String uri = intent.getDataString();
            txt.setText("Suggestion: "+ uri);

        }
    }

CitySuggestionProvider class:

public class CitySuggestionProvider extends ContentProvider {

    List<String> cities;

    @Override
    public boolean onCreate() {
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        if (cities == null || cities.isEmpty()){
            Log.d("NGVL", "WEB");
            List<CityPojo> pojos = new ArrayList<>();
            cities = new ArrayList<>();
            DatabaseHelper db = new DatabaseHelper(getContext());

            try {

                try {
                    db.create();
                } catch (IOException ioe) {
                    throw new Error("Unable to create database");
                }

                if (db.open()) {
                    pojos = db.getCities();
                }
                db.close();



                int lenght = pojos.size();
                for (int i = 0; i < lenght; i++) {
                    String city = pojos.get(i).getCity();
                    cities.add(city);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Log.d("NGVL", "Cache!");
        }

        MatrixCursor cursor = new MatrixCursor(
                new String[] {
                        BaseColumns._ID,
                        SearchManager.SUGGEST_COLUMN_TEXT_1,
                        SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID
                }
        );
        if (cities != null) {
            String query = uri.getLastPathSegment().toUpperCase();
            int limit = Integer.parseInt(uri.getQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT));

            int lenght = cities.size();
            for (int i = 0; i < lenght && cursor.getCount() < limit; i++) {
                String city = cities.get(i);
                if (city.toUpperCase().contains(query)){
                    cursor.addRow(new Object[]{ i, city, i });
                }
            }
        }
        return cursor;
    }


}

Manifest:

<activity
            android:name=".MainActivity"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <provider
            android:name=".CitySuggestionProvider"
            android:authorities="ngvl.android.demosearch.citysuggestion"
            android:enabled="true"
            android:exported="true"/>

        <activity android:name=".SearchableActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEARCH"/>
            </intent-filter>
            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable"/>
        </activity>

searchable.xml:

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
            android:hint="@string/hint_search"
            android:label="@string/app_name"
            android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"
            android:searchSuggestAuthority="ngvl.android.demosearch.citysuggestion"
            android:searchSuggestIntentAction="android.intent.action.VIEW"
            android:searchSuggestIntentData="content://ngvl.android.demosearch.city"/>

Everthing works fine I get the results just like this image:

enter image description here

but the problem is when I click on a suggestion I want to show its details in another activity. I have 2 text fields: city and country so when the user clicks the city in the suggestion I want to display its corresponding country in the details activity. I am not sure how to pass the country data to the details activity. I am using SQLite to get the data in the content provider class


Solution

  • I'm the author of the mentioned tutorial :) First of all, sorry for the sample is not clear enough, and let me try to explain it better.

    The content provider described in the sample should provides only search suggestions. So, when the user choose an option in the list a Uri is returned (in most of cases) to another provider. Notice that in the searchable configuration file (res/xml/searchable.xml) there is this property:

    content://ngvl.android.demosearch.city
    

    So, you should have a content provider to attend this Uri and return all details about the user selection. For this reason I just display the Uri in the second activity (SearchableActivity.java).

    However, I update the code to answer your question :) Now the suggestion provider is answering for both Uris :) This is the link for the commit. https://github.com/nglauber/playground/commit/51741babd301b42be220fc771c563da660808b20

    Let me know if you have any questions ;)

    Hope it helps!