使用适用于 android 的 google places api 网络服务搜索特定的附近地点

Posted

技术标签:

【中文标题】使用适用于 android 的 google places api 网络服务搜索特定的附近地点【英文标题】:Search specific nearby places using google places api web services for android 【发布时间】:2016-02-26 13:34:32 【问题描述】:

我正在尝试使用 google places api 网络服务将地点搜索类型限制为医院,但无法实现。

Logcat

java.lang.NullPointerException 在 com.ediode.graphics3d.ClinicFragment.sbMethod(ClinicFragment.java:174) 在 com.ediode.graphics3d.ClinicFragment.onMapReady(ClinicFragment.java:95)

MainActivity

public class ClinicFragment extends AppCompatActivity implements
    GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,
    LocationListener,
    OnMapReadyCallback
    
     private GoogleMap mGoogleMap;
    SupportMapFragment mapFrag;
    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    LatLng latLng;
    double mLatitude=0;
    double mLongitude=0;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    
    super.onCreate(savedInstanceState);

    setContentView(R.layout.clinic_fragment);

    mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
    mapFrag.getMapAsync(this);
    

    @Override
    public void onMapReady(GoogleMap googleMap)
    

    mGoogleMap = googleMap;
    mGoogleMap.setMyLocationEnabled(true);
    buildGoogleApiClient();
    mGoogleApiClient.connect();
    StringBuilder sbValue = new StringBuilder(sbMethod());
    PlacesTask placesTask = new PlacesTask();
    placesTask.execute(sbValue.toString());
    

    @Override
    public void onPause()
    
    super.onPause();
    //Unregister for location callbacks:
    if (mGoogleApiClient != null)
    
    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    
    

    protected synchronized void buildGoogleApiClient()
    
    mGoogleApiClient = new GoogleApiClient.Builder(this)
    .addConnectionCallbacks(this)
    .addOnConnectionFailedListener(this)
    .addApi(LocationServices.API)
    .build();
    

    @Override
    public void onConnected(Bundle bundle) throws SecurityException
    
    Toast.makeText(this,"Connected",Toast.LENGTH_SHORT).show();
    // Get LocationManager object from System Service LOCATION_SERVICE
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    // Create a criteria object to retrieve provider
    Criteria criteria = new Criteria();
    // Get the name of the best provider
    String provider = locationManager.getBestProvider(criteria, true);
    // Get Current Location
    Location myLocation = locationManager.getLastKnownLocation(provider);
    // Get latitude of the current location
    double latitude = myLocation.getLatitude();
    // Get longitude of the current location
    double longitude = myLocation.getLongitude();
    // Create a LatLng object for the current location
    latLng = new LatLng(latitude, longitude);

    //mGoogleMap.clear();
    //latLng = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude());
    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(latLng);
    markerOptions.title("Current Position");
    markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
    Marker m = mGoogleMap.addMarker(markerOptions);
    m.showInfoWindow();
    mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
    mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(11));
    Toast.makeText(this,"Touch the Pink Markers to View the Details of that Hospital",Toast.LENGTH_LONG).show();
    

    @Override
    public void onConnectionSuspended(int i) 
    Toast.makeText(this,"onConnectionSuspended",Toast.LENGTH_SHORT).show();
    

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) 
    Toast.makeText(this,"onConnectionFailed",Toast.LENGTH_SHORT).show();
    

    @Override
    public void onLocationChanged(Location location) 

    


    public StringBuilder sbMethod() throws SecurityException
    
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    Criteria criteria = new Criteria();
    String provider = locationManager.getBestProvider(criteria, true);
    Location myLocation = locationManager.getLastKnownLocation(provider);
    mLatitude=myLocation.getLatitude();
    mLongitude=myLocation.getLongitude();

    StringBuilder sb = new StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
    sb.append("location=" + mLatitude + "," + mLongitude);
    sb.append("&radius=20000");
    sb.append("&types=" + "hospital|doctor");
    sb.append("&sensor=true");

    sb.append("&key=***********************");

    Log.d("Map", "url: " + sb.toString());

    return sb;
    

    private class PlacesTask extends AsyncTask<String, Integer, String>
    

    String data = null;

// Invoked by execute() method of this object
@Override
protected String doInBackground(String... url) 
    try 
        data = downloadUrl(url[0]);
     catch (Exception e) 
        Log.d("Background Task", e.toString());
    
    return data;


// Executed after the complete execution of doInBackground() method
@Override
protected void onPostExecute(String result) 
    ParserTask parserTask = new ParserTask();

    // Start parsing the Google places in JSON format
    // Invokes the "doInBackground()" method of the class ParserTask
    parserTask.execute(result);


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", e.toString());
     finally 
        iStream.close();
        urlConnection.disconnect();
    
    return data;


private class ParserTask extends AsyncTask<String, Integer, List<HashMap<String, String>>> 

JSONObject jObject;

// Invoked by execute() method of this object
@Override
protected List<HashMap<String, String>> doInBackground(String... jsonData) 

    List<HashMap<String, String>> places = null;
    Place_JSON placeJson = new Place_JSON();

    try 
        jObject = new JSONObject(jsonData[0]);

        places = placeJson.parse(jObject);

     catch (Exception e) 
        Log.d("Exception", e.toString());
    
    return places;


// Executed after the complete execution of doInBackground() method
@Override
protected void onPostExecute(List<HashMap<String, String>> list) 

    Log.d("Map", "list size: " + list.size());
    // Clears all the existing markers;
    //mGoogleMap.clear();

    for (int i = 0; i < list.size(); i++) 

        // Creating a marker
        MarkerOptions markerOptions = new MarkerOptions();

        // Getting a place from the places list
        HashMap<String, String> hmPlace = list.get(i);


        // Getting latitude of the place
        double lat = Double.parseDouble(hmPlace.get("lat"));

        // Getting longitude of the place
        double lng = Double.parseDouble(hmPlace.get("lng"));

        // Getting name
        String name = hmPlace.get("place_name");

        Log.d("Map", "place: " + name);

        // Getting vicinity
        String vicinity = hmPlace.get("vicinity");

        latLng = new LatLng(lat, lng);

        // Setting the position for the marker
        markerOptions.position(latLng);

        markerOptions.title(name + " : " + vicinity);

        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));

        // Placing a marker on the touched position
        Marker m = mGoogleMap.addMarker(markerOptions);
       
      
    
    public class Place_JSON 

/**
 * 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("results");
     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 placeName = "-NA-";
    String vicinity = "-NA-";
    String latitude = "";
    String longitude = "";
    String reference = "";

    try 
        // Extracting Place name, if available
        if (!jPlace.isNull("name")) 
            placeName = jPlace.getString("name");
        

        // Extracting Place Vicinity, if available
        if (!jPlace.isNull("vicinity")) 
            vicinity = jPlace.getString("vicinity");
        

        latitude = jPlace.getJSONObject("geometry").getJSONObject("location").getString("lat");
        longitude = jPlace.getJSONObject("geometry").getJSONObject("location").getString("lng");
        reference = jPlace.getString("reference");

        place.put("place_name", placeName);
        place.put("vicinity", vicinity);
        place.put("lat", latitude);
        place.put("lng", longitude);
        place.put("reference", reference);

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


【问题讨论】:

可以添加 NullPointerException 的堆栈跟踪吗? 第 174 行的代码是什么? @DanielNugent 嘿,抱歉回复晚了,因为我正忙于其他工作。我已经编辑了我的问题。这就是我现在得到的。请问你能帮我解决这个问题吗? @NigamPatro 第 174 行 - mLatitude=myLocation.getLatitude(); 但是您还没有为条件设置任何值? 【参考方案1】:

首先,您连接到 GooglePlayServices,但从未实际使用 GooglePlayServices 作为位置。

而不是这个:

Location myLocation = locationManager.getLastKnownLocation(provider);

你可能想这样做:

Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
                mGoogleApiClient);

但是,这些方法总是有可能返回 null,因此请始终对上述方法的结果进行 null 检查。在调用 mLatitude=myLocation.getLatitude(); 之前,您没有对此位置对象进行空值检查是导致 NullPointerException 的原因。

但是,我也建议不要调用 getLastLocation(),因为它很容易返回 null。它也不会请求新位置,因此即使您返回位置,它也可能非常旧,并且无法反映设备的当前位置。最好注册一个监听器,即使你在收到第一个 onLocationChanged() 回调后取消注册。

看起来你基本上想结合this answer和this answer。

我只是基本做到了,还清理了一点代码。

这是整个类的代码:

import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MapsActivity2 extends AppCompatActivity
        implements OnMapReadyCallback,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener 

    GoogleMap mGoogleMap;
    SupportMapFragment mapFrag;
    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    Location mLastLocation;
    Marker mCurrLocationMarker;
    boolean firstRun = true;

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

        mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFrag.getMapAsync(this);
    

    @Override
    public void onPause() 
        super.onPause();

        //stop location updates when Activity is no longer active
        if (mGoogleApiClient != null) 
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        
    

    @Override
    public void onMapReady(GoogleMap googleMap)
    
        mGoogleMap=googleMap;
        mGoogleMap.setMyLocationEnabled(true);
        mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

        //Initialize Google Play Services
        buildGoogleApiClient();
        mGoogleApiClient.connect();
    

    public StringBuilder sbMethod(Location currentLocation) 
        //current location
        double mLatitude = currentLocation.getLatitude();
        double mLongitude = currentLocation.getLongitude();

        StringBuilder sb = new StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
        sb.append("location=" + mLatitude + "," + mLongitude);
        sb.append("&radius=5000");
        sb.append("&types=" + "restaurant");
        sb.append("&sensor=true");

        sb.append("&key=AIza********************");

        Log.d("Map", "<><>api: " + sb.toString());

        return sb;
    

    protected synchronized void buildGoogleApiClient() 
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    

    @Override
    public void onConnected(Bundle bundle) 
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    

    @Override
    public void onConnectionSuspended(int i) 

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) 

    @Override
    public void onLocationChanged(Location location)
    
        mLastLocation = location;
        if (mCurrLocationMarker != null) 
            mCurrLocationMarker.remove();
        

        //Place current location marker
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);

        //move map camera
        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(11));

        //query places with current location
        StringBuilder sbValue = new StringBuilder(sbMethod(location));
        PlacesTask placesTask = new PlacesTask();
        placesTask.execute(sbValue.toString());

        if (mGoogleApiClient != null) 
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        
    

    private class PlacesTask extends AsyncTask<String, Integer, String>
    

        String data = null;

        // Invoked by execute() method of this object
        @Override
        protected String doInBackground(String... url) 
            try 
                data = downloadUrl(url[0]);
             catch (Exception e) 
                Log.d("Background Task", e.toString());
            
            return data;
        

        // Executed after the complete execution of doInBackground() method
        @Override
        protected void onPostExecute(String result) 
            Log.d("result", "<><> result: " + result);
            ParserTask parserTask = new ParserTask();

            // Start parsing the Google places in JSON format
            // Invokes the "doInBackground()" method of the class ParserTask
            parserTask.execute(result);
        
    

    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", e.toString());
         finally 
            iStream.close();
            urlConnection.disconnect();
        
        return data;
    

    private class ParserTask extends AsyncTask<String, Integer, List<HashMap<String, String>>> 

        JSONObject jObject;

        // Invoked by execute() method of this object
        @Override
        protected List<HashMap<String, String>> doInBackground(String... jsonData) 

            List<HashMap<String, String>> places = null;
            Place_JSON placeJson = new Place_JSON();

            try 
                jObject = new JSONObject(jsonData[0]);

                places = placeJson.parse(jObject);

             catch (Exception e) 
                Log.d("Exception", e.toString());
            
            return places;
        

        // Executed after the complete execution of doInBackground() method
        @Override
        protected void onPostExecute(List<HashMap<String, String>> list) 

            Log.d("Map", "list size: " + list.size());
            // Clears all the existing markers;
            if (!firstRun) 

                mGoogleMap.clear();
            
            firstRun = false;

            for (int i = 0; i < list.size(); i++) 

                // Creating a marker
                MarkerOptions markerOptions = new MarkerOptions();

                // Getting a place from the places list
                HashMap<String, String> hmPlace = list.get(i);


                // Getting latitude of the place
                double lat = Double.parseDouble(hmPlace.get("lat"));

                // Getting longitude of the place
                double lng = Double.parseDouble(hmPlace.get("lng"));

                // Getting name
                String name = hmPlace.get("place_name");

                Log.d("Map", "place: " + name);

                // Getting vicinity
                String vicinity = hmPlace.get("vicinity");

                LatLng latLng = new LatLng(lat, lng);

                // Setting the position for the marker
                markerOptions.position(latLng);

                markerOptions.title(name + " : " + vicinity);

                markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));

                // Placing a marker on the touched position
                Marker m = mGoogleMap.addMarker(markerOptions);

            
        
    
    public class Place_JSON 

        /**
         * 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("results");
             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 placeName = "-NA-";
            String vicinity = "-NA-";
            String latitude = "";
            String longitude = "";
            String reference = "";

            try 
                // Extracting Place name, if available
                if (!jPlace.isNull("name")) 
                    placeName = jPlace.getString("name");
                

                // Extracting Place Vicinity, if available
                if (!jPlace.isNull("vicinity")) 
                    vicinity = jPlace.getString("vicinity");
                

                latitude = jPlace.getJSONObject("geometry").getJSONObject("location").getString("lat");
                longitude = jPlace.getJSONObject("geometry").getJSONObject("location").getString("lng");
                reference = jPlace.getString("reference");

                place.put("place_name", placeName);
                place.put("vicinity", vicinity);
                place.put("lat", latitude);
                place.put("lng", longitude);
                place.put("reference", reference);

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


结果:

【讨论】:

仍然报错。 java.lang.NullPointerException at com.ediode.graphics3d.ClinicFragment$ParserTask.onPostExecute(ClinicFragment.java:268) at com.ediode.graphics3d.ClinicFragment$ParserTask.onPostExecute(ClinicFragment.java:242) @User0706 您可以添加完整的堆栈跟踪,并更新问题中的代码吗?第 268 行是什么? 已更新。看看吧 @User0706 查看此行输出的日志:Log.d("Map", "api url: " + sb.toString());,然后在浏览器中尝试该 url。 我现在可以看到我当前的位置,但附近的医院不可见

以上是关于使用适用于 android 的 google places api 网络服务搜索特定的附近地点的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 KML 数据检索适用于 Android 的 Google 路线不再有效? [复制]

获取适用于 Android 的 Google Places API 密钥

适用于 Android 的 Google 登录 - 发布与调试

如何使用适用于 Android V2 的 Google Maps 处理地图移动端?

适用于 Android 的 Unity Google Play 游戏,Xcode 中出现 +200 错误

google 的 Map SDK 计费如何适用于 Android 和 iOS 应用程序?