Android SearchView widget with Google Places API using ActionBarSherlock library

July 18, 2013
By

In this article, we will develop an Android application that can search Google Places API using SearchView widget and show the results in Google Maps Android API V2. In this application the searchview widget is placed in action bar.

We know that, the SearchView widget is available only since Android API level 11. So will use ActionBarSherlock library for the backward compatibility.

Major files used in this application are listed below :

  • MainActivity.java : The search action is placed in the action bar of the MainActivity.
  • searchable.xml : This is the configuration file for search dialog which defines content provider and suggestion properties.
  • PlaceProvider.java : The content provider for fetching places from Google places autocomplete API.
  • PlaceJSONParser.java : Parses the result of Google Places Autocomplete API.
  • PlaceDetailsJSONParser.java : Parses the result of Google Places Details API.

This application is developed in Eclipse (4.2.1) with ADT plugin (22.0.1) and Android SDK (22.0.1) and tested in real devices with Android versions 2.3.6  ( GingerBread ) and 4.1.2 ( Jelly Bean ).

An alternative to this application is available in “Adding Google Places Autocomplete API as custom suggestions in Android Search Dialog“, where we have used SearchDialog window for searching places.


1. Create new Android application project

Application Name : LocationSherlockSearchViewMapV2

Project Name : LocationSherlockSearchViewMapV2

Package Name : in.wptrafficanalyzer.locationsherlocksearchviewmapv2

Minimum Required SDK : API 8 : Android 2.2 ( Froyo )

Target SDK : API 17 : Android 4.2 ( Jelly Bean )


2. Delete Android Support library from this project

In this application, we are using ActionBarSherlock library for the backward compatibility support of Android versions. Since ActionBarSherlock library already contains the Android Support library, we have to delete the Android Support Library (android-support-v4.jar)  from this project, if it is added automatically by Eclipse IDE.

We can delete the library file at libs/android-support-v4.jar .


3. Setup ActionBarSherlock library in Eclipse

In order to setup ActionBarSherlock library, please refer the article titled “Setting up Action Bar Sherlock Library 4.3.1 for Eclipse IDE


4. Clean and Build ActionBarSherlock library project in Eclipse

Clean and Build ActionBarSherlock library project

Figure 1 : Clean and Build ActionBarSherlock library project


5. Link this project to ActionBarSherlock library

Link this project to ActionBarSherlock library

Figure 2 : Link this project to ActionBarSherlock library


6. Download and configure Google Play Services Library in Eclipse

Please follow the given below link to setup Google Play Service library in Eclipse.

http://developer.android.com/google/play-services/setup.html


7. Link this project to Google Play Service library

Link this project to Google Play Service Library

Figure 3 : Link this project to Google Play Service Library


8. Get the API key for Google Maps Android API V2

We need to get an API key from Google to use Google Maps in Android application.

Please follow the given below link to get the API key for Google Maps Android API v2.

https://developers.google.com/maps/documentation/android/start


9. Get the API key for Google Places API

We can create API key for Google Place API by clicking “Create new Browser key”  available at the “API Access” pane of the Google console URL : http://code.google.com/apis/console.

Also ensure that, “Places API” is enabled in the “Services” pane of the Google console.


10. Update the file res/values/strings.xml


<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">SearchView Demo</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_search">Search</string>
    <string name="search_hint">Search Places</string>
    <string name="search_settings">Search Places</string>

</resources>


11. Update the layout file res/layout/activity_main.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <fragment
        android:id="@+id/map"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>


12. Update the menu file res/menu/main.xml


<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/action_search"
        android:orderInCategory="100"
        android:showAsAction="ifRoom"
        android:title="@string/action_search"
        android:actionViewClass="com.actionbarsherlock.widget.SearchView"/>

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_settings"/>

</menu>


13. Create the class file src/in/wptrafficanalyzer/locationsherlocksearchviewmapv2/PlaceJSONParser.java

package in.wptrafficanalyzer.locationsherlocksearchviewmapv2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class PlaceJSONParser {

    /** Receives a JSONObject and returns a list */
    public List<HashMap<String,String>> parse(JSONObject jObject){

        JSONArray jPlaces = null;
        try {
            /** Retrieves all the elements in the 'places' array */
            jPlaces = jObject.getJSONArray("predictions");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        /** Invoking getPlaces with the array of json object
        * where each json object represent a place
        */
        return getPlaces(jPlaces);
    }

    private List<HashMap<String, String>> getPlaces(JSONArray jPlaces){
        int placesCount = jPlaces.length();
        List<HashMap<String, String>> placesList = new ArrayList<HashMap<String,String>>();
        HashMap<String, String> place = null;

        /** Taking each place, parses and adds to list object */
        for(int i=0; i<placesCount;i++){
            try {
                /** Call getPlace with place JSON object to parse the place */
                place = getPlace((JSONObject)jPlaces.get(i));
                placesList.add(place);

            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        return placesList;
    }

    /** Parsing the Place JSON object */
    private HashMap<String, String> getPlace(JSONObject jPlace){

        HashMap<String, String> place = new HashMap<String, String>();

        String id="";
        String reference="";
        String description="";

        try {

            description = jPlace.getString("description");
            id = jPlace.getString("id");
            reference = jPlace.getString("reference");

            place.put("description", description);
            place.put("_id",id);
            place.put("reference",reference);

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return place;
    }
}


14. Create the class file src/in/wptrafficanalyzer/locationsherlocksearchviewmapv2/PlaceDetailsJSONParser.java

package in.wptrafficanalyzer.locationsherlocksearchviewmapv2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

public class PlaceDetailsJSONParser {

    /** Receives a JSONObject and returns a list */
    public List<HashMap<String,String>> parse(JSONObject jObject){

        Double lat = Double.valueOf(0);
        Double lng = Double.valueOf(0);
        String formattedAddress = "";

        HashMap<String, String> hm = new HashMap<String, String>();
        List<HashMap<String, String>> list = new ArrayList<HashMap<String,String>>();

        try {
            lat = (Double)jObject.getJSONObject("result").getJSONObject("geometry").getJSONObject("location").get("lat");
            lng = (Double)jObject.getJSONObject("result").getJSONObject("geometry").getJSONObject("location").get("lng");
            formattedAddress = (String) jObject.getJSONObject("result").get("formatted_address");

        } catch (JSONException e) {
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }

        hm.put("lat", Double.toString(lat));
        hm.put("lng", Double.toString(lng));
        hm.put("formatted_address",formattedAddress);

        list.add(hm);

        return list;
    }
}

15. Create the file src/in/wptrafficanalyzer/locationsherlocksearchviewmapv2/PlaceProvider.java

package in.wptrafficanalyzer.locationsherlocksearchviewmapv2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;

public class PlaceProvider extends ContentProvider {

    public static final String AUTHORITY = "in.wptrafficanalyzer.locationsherlocksearchviewmapv2.PlaceProvider";

    public static final Uri SEARCH_URI = Uri.parse("content://"+AUTHORITY+"/search");

    public static final Uri DETAILS_URI = Uri.parse("content://"+AUTHORITY+"/details");

    private static final int SEARCH = 1;
    private static final int SUGGESTIONS = 2;
    private static final int DETAILS = 3;

    // Obtain browser key from https://code.google.com/apis/console
    String mKey = "key=YOUR_BROWSER_KEY";

    // Defines a set of uris allowed with this content provider
    private static final UriMatcher mUriMatcher = buildUriMatcher();

    private static UriMatcher buildUriMatcher() {

        UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

        // URI for "Go" button
        uriMatcher.addURI(AUTHORITY, "search", SEARCH );

        // URI for suggestions in Search Dialog
        uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,SUGGESTIONS);

        // URI for Details
        uriMatcher.addURI(AUTHORITY, "details",DETAILS);

        return uriMatcher;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
        Cursor c = null;

        PlaceJSONParser parser = new PlaceJSONParser();
        PlaceDetailsJSONParser detailsParser = new PlaceDetailsJSONParser();

        String jsonString = "";
        String jsonPlaceDetails = "";

        List<HashMap<String, String>> list = null;
        List<HashMap<String, String>> detailsList = null;

        MatrixCursor mCursor = null;

        switch(mUriMatcher.match(uri)){
        case SEARCH:
            // Defining a cursor object with columns description, lat and lng
            mCursor = new MatrixCursor(new String[] { "description","lat","lng" });

            // Create a parser object to parse places in JSON format
            parser = new PlaceJSONParser();

            // Create a parser object to parse place details in JSON format
            detailsParser = new PlaceDetailsJSONParser();

            // Get Places from Google Places API
            jsonString = getPlaces(selectionArgs);
            try {
                // Parse the places ( JSON => List )
                list = parser.parse(new JSONObject(jsonString));

                // Finding latitude and longitude for each places using Google Places Details API
                for(int i=0;i<list.size();i++){
                    HashMap<String, String> hMap = (HashMap<String, String>) list.get(i);

                    detailsParser =new PlaceDetailsJSONParser();

                    // Get Place details
                    jsonPlaceDetails = getPlaceDetails(hMap.get("reference"));

                    // Parse the details ( JSON => List )
                    detailsList = detailsParser.parse(new JSONObject(jsonPlaceDetails));

                    // Creating cursor object with places
                    for(int j=0;j<detailsList.size();j++){
                        HashMap<String, String> hMapDetails = detailsList.get(j);

                        // Adding place details to cursor
                        mCursor.addRow(new String[]{ hMap.get("description") , hMapDetails.get("lat") , hMapDetails.get("lng") });
                    }

                }
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            c = mCursor;
            break;

        case SUGGESTIONS :

            // Defining a cursor object with columns id, SUGGEST_COLUMN_TEXT_1, SUGGEST_COLUMN_INTENT_EXTRA_DATA
            mCursor = new MatrixCursor(new String[] { "_id", SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA } );

            // Creating a parser object to parse places in JSON format
            parser = new PlaceJSONParser();

            // Get Places from Google Places API
            jsonString = getPlaces(selectionArgs);

            try {
                // Parse the places ( JSON => List )
                list = parser.parse(new JSONObject(jsonString));

                // Creating cursor object with places
                for(int i=0;i<list.size();i++){
                    HashMap<String, String> hMap = (HashMap<String, String>) list.get(i);

                    // Adding place details to cursor
                    mCursor.addRow(new String[] { Integer.toString(i), hMap.get("description"), hMap.get("reference") });
                }
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            c = mCursor;
            break;

        case DETAILS :
            // Defining a cursor object with columns description, lat and lng
            mCursor = new MatrixCursor(new String[] { "description","lat","lng" });

            detailsParser = new PlaceDetailsJSONParser();
            jsonPlaceDetails = getPlaceDetails(selectionArgs[0]);
            try {
                detailsList = detailsParser.parse(new JSONObject(jsonPlaceDetails));
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            for(int j=0;j<detailsList.size();j++){
                HashMap<String, String> hMapDetails = detailsList.get(j);
                mCursor.addRow(new String[]{ hMapDetails.get("formatted_address") , hMapDetails.get("lat") , hMapDetails.get("lng") });
            }
            c = mCursor;
            break;
        }
        return c;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
        String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }

    /** A method to download json data from url */
    private String downloadUrl(String strUrl) throws IOException{
        String data = "";
        InputStream iStream = null;
        HttpURLConnection urlConnection = null;
        try{
            URL url = new URL(strUrl);

            // Creating an http connection to communicate with url
            urlConnection = (HttpURLConnection) url.openConnection();

            // Connecting to url
            urlConnection.connect();

            // Reading data from url
            iStream = urlConnection.getInputStream();

            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));

            StringBuffer sb = new StringBuffer();

            String line = "";
            while( ( line = br.readLine()) != null){
                sb.append(line);
            }

            data = sb.toString();

            br.close();

        }catch(Exception e){
           Log.d("Exception while downloading url", e.toString());
        }finally{
            iStream.close();
            urlConnection.disconnect();
        }
        return data;
    }

    private String getPlaceDetailsUrl(String ref){

        // reference of place
        String reference = "reference="+ref;

        // Sensor enabled
        String sensor = "sensor=false";

        // Building the parameters to the web service
        String parameters = reference+"&"+sensor+"&"+mKey;

        // Output format
        String output = "json";

        // Building the url to the web service
        String url = "https://maps.googleapis.com/maps/api/place/details/"+output+"?"+parameters;

        return url;
    }

    private String getPlacesUrl(String qry){

        try {
            qry = "input=" + URLEncoder.encode(qry, "utf-8");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }

        // Sensor enabled
        String sensor = "sensor=false";

        // place type to be searched
        String types = "types=geocode";

        // Building the parameters to the web service
        String parameters = qry+"&"+types+"&"+sensor+"&"+mKey;

        // Output format
        String output = "json";
        // Building the url to the web service
        String url = "https://maps.googleapis.com/maps/api/place/autocomplete/"+output+"?"+parameters;
        return url;
    }

    private String getPlaces(String[] params){
        // For storing data from web service
        String data = "";
        String url = getPlacesUrl(params[0]);
        try{
            // Fetching the data from web service in background
            data = downloadUrl(url);
        }catch(Exception e){
            Log.d("Background Task",e.toString());
        }
        return data;
    }

    private String getPlaceDetails(String reference){
        String data = "";
        String url = getPlaceDetailsUrl(reference);
        try {
            data = downloadUrl(url);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }
}

Note : Update “YOUR_BROWSER_KEY on line 39 with the browser key obtained in Step 9.


16. Update the class MainActivity in the file src/in/wptrafficanalyzer/locationsherlocksearchviewmapv2/MainActivity.java


package in.wptrafficanalyzer.locationsherlocksearchviewmapv2;

import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;

import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.widget.SearchView;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends SherlockFragmentActivity implements LoaderCallbacks<Cursor>{

    GoogleMap mGoogleMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SupportMapFragment fragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mGoogleMap = fragment.getMap();

        handleIntent(getIntent());
    }

    private void handleIntent(Intent intent){
        if(intent.getAction().equals(Intent.ACTION_SEARCH)){
            doSearch(intent.getStringExtra(SearchManager.QUERY));
        }else if(intent.getAction().equals(Intent.ACTION_VIEW)){
            getPlace(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        handleIntent(intent);
    }

    private void doSearch(String query){
        Bundle data = new Bundle();
        data.putString("query", query);
        getSupportLoaderManager().restartLoader(0, data, this);
    }

    private void getPlace(String query){
        Bundle data = new Bundle();
        data.putString("query", query);
        getSupportLoaderManager().restartLoader(1, data, this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getSupportMenuInflater().inflate(R.menu.main, menu);

        // Get the SearchView and set the searchable configuration
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

        return true;
    }

    @Override
    public Loader<Cursor> onCreateLoader(int arg0, Bundle query) {
        CursorLoader cLoader = null;
        if(arg0==0)
            cLoader = new CursorLoader(getBaseContext(), PlaceProvider.SEARCH_URI, null, null, new String[]{ query.getString("query") }, null);
        else if(arg0==1)
            cLoader = new CursorLoader(getBaseContext(), PlaceProvider.DETAILS_URI, null, null, new String[]{ query.getString("query") }, null);
        return cLoader;

    }

    @Override
    public void onLoadFinished(Loader<Cursor> arg0, Cursor c) {
        showLocations(c);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> arg0) {
        // TODO Auto-generated method stub
    }

    private void showLocations(Cursor c){
        MarkerOptions markerOptions = null;
        LatLng position = null;
        mGoogleMap.clear();
        while(c.moveToNext()){
            markerOptions = new MarkerOptions();
            position = new LatLng(Double.parseDouble(c.getString(1)),Double.parseDouble(c.getString(2)));
            markerOptions.position(position);
            markerOptions.title(c.getString(0));
            mGoogleMap.addMarker(markerOptions);
        }
        if(position!=null){
            CameraUpdate cameraPosition = CameraUpdateFactory.newLatLng(position);
            mGoogleMap.animateCamera(cameraPosition);
        }
    }
}


17. Update the configuration file /res/xml/searchable.xml


<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/search_hint"
    android:searchSettingsDescription="@string/search_settings"

    android:searchSuggestAuthority="in.wptrafficanalyzer.locationsherlocksearchviewmapv2.PlaceProvider"
    android:searchSuggestIntentAction="android.intent.action.VIEW"
    android:searchSuggestSelection=" ?"
    android:searchSuggestThreshold="2" >

</searchable>


18. Update the file AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="in.wptrafficanalyzer.locationsherlocksearchviewmapv2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <!-- Protect the map component of the application using application signature -->
    <permission
        android:name="in.wptrafficanalyzer.locationsherlocksearchviewmapv2.permission.MAPS_RECEIVE"
        android:protectionLevel="signature" />

    <!-- Allows to receive map -->
    <uses-permission android:name="in.wptrafficanalyzer.locationsherlocksearchviewmapv2.permission.MAPS_RECEIVE" />

    <!-- Used by the Google Maps Android API V2 to download map tiles from Google Maps servers -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Allows the Google Maps Android API V2 to cache map tile data in the device's external storage area -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!-- Allows the Google Maps Android API V2 to use WiFi or mobile cell data (or both) to determine the device's location -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <!-- Allows the Google Maps Android API V2 to use the Global Positioning System (GPS)
    to determine the device's location to within a very small area -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <!-- Allows to contact Google Serves -->
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />

    <!-- Google Maps Android API V2 requires OpenGL ES version 2 -->
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.Sherlock" >
        <activity
            android:name="in.wptrafficanalyzer.locationsherlocksearchviewmapv2.MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>

            <!-- Points to searchable activity -->
            <meta-data android:name="android.app.default_searchable"
                android:value=".MainActivity" />

            <!-- Points to searchable meta data -->
            <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable"/>

        </activity>

        <provider
            android:name=".PlaceProvider"
            android:authorities="in.wptrafficanalyzer.locationsherlocksearchviewmapv2.PlaceProvider"
            android:exported="false" />

        <!-- Specifies the Android API Key, which is obtained from Google API Console -->
        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="YOUR_ANDROID_API_KEY" />
    </application>
</manifest>

Note : Update “YOUR_ANDROID_API_KEY on line 77 with the browser key obtained in Step 8.


19. Screenshots of the application

MainActivity of the application

Figure 4 : MainActivity of the application

Searching a place using SuggestView widget

Figure 5 : Searching a place using SuggestView widget

Showing result in Google Maps Android API V2

Figure 6 : Showing result in Google Maps Android API V2


20. Download Source code


How to hire me?

I am George Mathew, working as software architect and Android app developer at wptrafficanalyzer.in

You can hire me on hourly basis or on project basis for Android applications development.

For hiring me, please mail your requirements to info@wptrafficanalyzer.in.

My other blogs
store4js.blogspot.com


Android Knowledge Quiz

Ready to test your knowledge in Android? Take this quiz :



Tags: , , , , , , , , , ,

18 Responses to Android SearchView widget with Google Places API using ActionBarSherlock library

  1. Linea on July 26, 2013 at 9:15 am

    It works perfectly, thank you..
    may i ask you what is URI authority? Is it same as the package name?

    • george on July 26, 2013 at 9:49 am

      == what is URI authority? ==
      URI authority is the identifier of the content provider. This is used in AndroidManifest.xml to declare the content provider.

      == Is it same as the package name? ==
      It is just a custom to use the same name as the package name.

      • Linea on July 30, 2013 at 11:34 pm

        It works perfectly when I use it as the MainActivity. However, the app crash when I try to intent to this activity from the main activity.
        Below is the error log:

        E/AndroidRuntime(5539): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.Android.search/com.Android.search.Map}: java.lang.NullPointerException
        E/AndroidRuntime(5539): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
        E/AndroidRuntime(5539): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
        E/AndroidRuntime(5539): at android.app.ActivityThread.access$600(ActivityThread.java:141)
        E/AndroidRuntime(5539): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
        E/AndroidRuntime(5539): at android.os.Handler.dispatchMessage(Handler.java:99)
        E/AndroidRuntime(5539): at android.os.Looper.loop(Looper.java:137)
        E/AndroidRuntime(5539): at android.app.ActivityThread.main(ActivityThread.java:5041)
        E/AndroidRuntime(5539): at java.lang.reflect.Method.invokeNative(Native Method)
        E/AndroidRuntime(5539): at java.lang.reflect.Method.invoke(Method.java:511)
        E/AndroidRuntime(5539): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
        E/AndroidRuntime(5539): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
        E/AndroidRuntime(5539): at dalvik.system.NativeStart.main(Native Method)
        E/AndroidRuntime(5539): Caused by: java.lang.NullPointerException
        E/AndroidRuntime(5539): at com.Android.search.Map.handleIntent(NearbyHawker.java:473)
        E/AndroidRuntime(5539): at com.Android.search.Map.onCreate(NearbyHawker.java:129)
        E/AndroidRuntime(5539): at android.app.Activity.performCreate(Activity.java:5104)
        E/AndroidRuntime(5539): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
        E/AndroidRuntime(5539): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)

        I have modified the Manifest.

        Do you have any idea why this happens?

        Thank you

  2. Linea on August 4, 2013 at 5:36 pm

    Problem solved, modify the handleIntent() as
    if(Intent.ACTION_SEARCH.equals(intent.getAction()))
    {
    String query = intent.getStringExtra(SearchManager.QUERY);
    doSearch(query);
    }
    else if(Intent.ACTION_VIEW.equals(intent.getAction()))
    {
    getPlace(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
    }

    • george on August 6, 2013 at 6:35 am

      Hi Linea,

      What is the difference between this and the previous one?

      • Linea on August 6, 2013 at 12:01 pm

        The modified code and your original code look almost the same. The only difference is my modified code using Intent.ACTION_SEARCH.equals(intent.getAction()and Intent.ACTION_VIEW.equals(intent.getAction()as the if-else condition, whereas your original code using intent.getAction().equals(Intent.ACTION_SEARCH)and intent.getAction().equals(Intent.ACTION_VIEW). I have referenced http://developer.android.com/training/search/setup.html and modified my handleIntent() accordingly. I have no idea why your code works well only when the searchable activity is a launcher activity, but it doesn’t work when I try to intent to this activity from another activity.

  3. Anish Panthi on August 22, 2013 at 3:53 pm

    Hi.. thankx for ur post. but whenever i tried to search the following error appears on CatLog and no searched is done. Here is my error:
    SpannableStringBuilder SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
    what can I do to correct this error? I’m running in mobile device not in emulator.

  4. Ant Soa on September 1, 2013 at 9:41 pm

    I have one question. Why do we need to use the content provider? Is it possible to implement the search directly the google places api an displaying the results from search?

  5. Andrey Bukhman on February 27, 2014 at 9:07 pm

    Hi George.
    Do you know how i can realize the search in google maps?
    Search line need to be direct on google maps
    I want to save place.

    Thanks Andrey

  6. Scott Philips on April 28, 2014 at 4:32 am

    Very useful code, nicely done.

  7. Vishal Jevtani on January 11, 2015 at 6:27 pm

    this code is perfectly running. however there is one problem I am facing. Every time I click on a query that will place marker on map, a new activity is created by LoaderManager, I want to map every query in a single activity.

  8. Aexander on March 23, 2015 at 4:53 pm

    Good afternoon. How can I pause for 1 second delay calling query data from Google Place Api?
    It is necessary that the user has finished typing a word, without sending a request for each character entered.
    The problem is that it is necessary to wait until the user has finished typing a word.
    Otherwise cases are multiple access Place API that can deplete the query limit

  9. Aexander on March 24, 2015 at 3:07 pm

    Good afternoon. How can I pause for 1 second delay calling query data from Google Place Api?
    It is necessary that the user has finished typing a word, without sending a request for each character entered.
    The problem is that it is necessary to wait until the user has finished typing a word.
    Otherwise cases are multiple access Place API that can deplete the query limit

  10. Adrian on May 7, 2015 at 4:51 am

    Generaly I have HUGE problems with the fact that I need to use Sherlock. I have drawer done and I can’t use sherlock library. In that case my SearchView is simply nullpointer. SearchView from appcompatv7 is not compatabile. Any hints how to overcome this obstacle?

    Anyway it’s very good piece of code, well done.

  11. imtiez on August 26, 2015 at 1:20 am

    I have this problem
    failed to find provider info for in.wptrafficanalyzer.locationsherlocksearchviewmapv2.PlaceProvider

  12. Nabanita on December 22, 2015 at 1:10 pm

    whta is browser key? shall i need to pay for creation of broser key?

  13. Bhavin on May 2, 2016 at 4:39 pm

    Hi George.
    How can I set searchview at bottom and search from that?
    pleas help me I can’t understand how to do it?

Leave a Reply to Bhavin Cancel reply

Your email address will not be published. Required fields are marked *

Be friend at g+

Subscribe for Lastest Updates

FBFPowered by ®Google Feedburner