MapView片段上的PlaceAutocomplete小部件

时间:2016-03-01 09:08:16

标签: android android-fragments google-places-api android-maps-v2

我正在尝试创建一个叠加在其上的PlaceAutocomplete小部件的mapview。 此视图的功能是计算从当前位置到我在PlaceAutocomplete小部件中选择的位置的距离。

为了更好地解释自己,我需要一个类似的片段,就像谷歌地图应用程序一样。目前我已经创建了一个显示地图的片段。然后,此视图将由PlaceAutocomplete小部件覆盖。

目前,我可以在启动mapview时获取当前位置。 (截图1)然而,当我尝试搜索目的地时(截屏2),小部件只显示我选择的目的地,而不调用Google Directions API来获取从我的位置到目的地的公交路线。 (截图3)

从我的logcat,我可以看到构建URL并调用Google Directions API的方法甚至没有被调用。

这是我的代码:

public class GeoFragment extends Fragment implements PlaceSelectionListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    GoogleMap map;
    SupportMapFragment mapFragment;

    private LocationRequest lr;
    private GoogleApiClient apiClient;
    private static View view;
    private Location location;

    int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1;
    int RESULT_OK = 2;
    int RESULT_CANCELED = 3;
    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
    final String GOOGLE_KEY;
    int PLACE_PICKER_REQUEST = 1;

    double currentLatitude;
    double currentLongitude;
    SupportPlaceAutocompleteFragment searcher;
    String placeString;

    public GeoFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        buildGoogleApiClient();

        if (view != null) {
            ViewGroup parent = (ViewGroup) view.getParent();
            if (parent != null)
                parent.removeView(view);
        }

        try {
            view = inflater.inflate(R.layout.layout_map, container, false);

            mapFragment = ((SupportMapFragment) this.getChildFragmentManager().findFragmentById(R.id.mapView));
            searcher = (SupportPlaceAutocompleteFragment) this.getChildFragmentManager().findFragmentById(R.id.info_text);
            //searcher.setBoundsBias(new LatLngBounds(new LatLng(), new LatLng()));

            map = mapFragment.getMap();
            map.getUiSettings().setAllGesturesEnabled(true);
            map.getUiSettings().setMyLocationButtonEnabled(true);
            map.setMyLocationEnabled(true);
            map.getUiSettings().setZoomControlsEnabled(false);

            map.animateCamera(CameraUpdateFactory.zoomIn());
            map.animateCamera(CameraUpdateFactory.zoomTo(15), 2000, null);
            map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(currentLatitude, currentLongitude), 19));

            MapsInitializer.initialize(this.getActivity());
        } catch (InflateException e) {
            Toast.makeText(getActivity(), "Problems inflating the view !",
                    Toast.LENGTH_LONG).show();
        } catch (NullPointerException e) {
            Log.e("GServices Error", e.toString());
        }

        return view;
    }

    protected synchronized void buildGoogleApiClient() {
        apiClient = new GoogleApiClient.Builder(getActivity().getApplicationContext())
                .addApi(LocationServices.API)
                .addApi(Places.GEO_DATA_API)
                .addApi(Places.PLACE_DETECTION_API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }

    private boolean checkPlayServices() {
        int resultCode = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(getActivity().getApplicationContext());
        if (resultCode != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                GooglePlayServicesUtil.getErrorDialog(resultCode, getActivity(), PLAY_SERVICES_RESOLUTION_REQUEST).show();
            }
            return false;
        }
        return true;
    }

    @Override
    public void onStart() {
        super.onStart();
        if (apiClient != null) {
            apiClient.connect();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if (apiClient.isConnected()) {
            apiClient.disconnect();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        stopLocationUpdates();
    }

    @Override
    public void onResume() {
        super.onResume();

        checkPlayServices();

        // Resuming the periodic location updates
        if (apiClient.isConnected()) {
            startLocationUpdates();
        }
    }

    protected void startLocationUpdates() {

        LocationServices.FusedLocationApi.requestLocationUpdates(
                apiClient, lr, this);

    }

    protected void stopLocationUpdates() {
        LocationServices.FusedLocationApi.removeLocationUpdates(
                apiClient, this);
    }

    public void getCoordinates(){

        location = LocationServices.FusedLocationApi.getLastLocation(apiClient);

        if (location != null) {
            currentLatitude = location.getLatitude();
            currentLongitude = location.getLongitude();
        }
    }

    @Override
    public void onLocationChanged(Location loc) {

        location = loc;
        getCoordinates();

        map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(currentLatitude, currentLongitude), 19));

    }

    @Override
    public void onConnected(Bundle connectionHint) {

        if (location == null) {
            lr = LocationRequest.create();
            lr.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            lr.setInterval(1000);
            LocationServices.FusedLocationApi.requestLocationUpdates(apiClient, lr, this);

        }
        //getCoordinates();
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        Log.i("Map Connection Failed", "Connection failed: ConnectionResult.getErrorCode() = "
                + result.getErrorCode());
    }

    public void onConnectionSuspended(int arg0) {
        apiClient.connect();
    }

    public void SearchPlace(String place) throws GooglePlayServicesNotAvailableException, GooglePlayServicesRepairableException {
        PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();

        startActivityForResult(builder.build(getActivity()), PLACE_PICKER_REQUEST);

        callPlaces(currentLongitude, currentLatitude, place);
    }

    public void callPlaces(final double longitude, final double latitude, final String destination) {
        String tag_string_req = "req_places";

        String url =  "https://maps.googleapis.com/maps/api/directions/json?origin=" + latitude + "," + longitude + "&destination="+ destination +"&alternatives=true&mode=transit&region=mt&key=" + getResources().getString(R.string.google_places_key);

        StringRequest strReq = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {

            @Override
            public void onResponse(String response) {
                    drawPath(response);
            }
        }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    Log.e("Error", "Registration Error: " + error.getMessage());
                    Toast.makeText(getActivity().getApplicationContext(),
                            error.getMessage(), Toast.LENGTH_LONG).show();
                }
        });

        AppController.getInstance().addToRequestQueue(strReq);

    }

    public void drawPath(String result){
        try {
            final JSONObject jsonObject = new JSONObject(result);

            JSONArray routeArray = jsonObject.getJSONArray("routes");
            JSONObject routes = routeArray.getJSONObject(0);


            JSONObject overviewPolylines = routes.getJSONObject("overview_polyline");
            String encodedString = overviewPolylines.getString("points");

            String statusString = jsonObject.getString("status");

            Log.d("test: ", encodedString);
            List<LatLng> list = decodePoly(encodedString);

            LatLng last = null;
            for (int i = 0; i < list.size()-1; i++) {
                LatLng src = list.get(i);
                LatLng dest = list.get(i+1);
                last = dest;
                Log.d("Last latLng:", last.latitude + ", " + last.longitude );
                Polyline line = map.addPolyline(new PolylineOptions()
                        .add(new LatLng(src.latitude, src.longitude), new LatLng(dest.latitude, dest.longitude))
                        .width(4)
                        .color(Color.GREEN));
            }

            Log.d("Last latLng:", last.latitude + ", " + last.longitude );
        }catch (JSONException e){
            e.printStackTrace();
        }
        catch(ArrayIndexOutOfBoundsException e) {
            System.err.println("Caught ArrayIndexOutOfBoundsException: "+ e.getMessage());
        }
    }

    private List<LatLng> decodePoly(String encoded){


        List<LatLng> poly = new ArrayList<LatLng>();
        int index = 0;
        int length = encoded.length();

        int latitude = 0;
        int longitude = 0;

        while(index < length){
            int b;
            int shift = 0;
            int result = 0;

            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);

            int destLat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            latitude += destLat;

            shift = 0;
            result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b > 0x20);

            int destLong = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            longitude += destLong;

            poly.add(new LatLng((latitude / 1E5),(longitude / 1E5) ));
        }
        return poly;
    }

    @Override
    public void onPlaceSelected(Place place) {
        Log.i("Destination", "Place Selected: " + place.getName());

        placeString = place.getName().toString();

        CharSequence attributions = place.getAttributions();
        if (!TextUtils.isEmpty(attributions)) {

            try {
                SearchPlace(placeString);
            } catch (GooglePlayServicesNotAvailableException e) {
                e.printStackTrace();
            } catch (GooglePlayServicesRepairableException e) {
                e.printStackTrace();
            }
        } else {
            searcher.setText("Where shall we take you today?");
        }

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        searcher.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onError(Status status) {
        Log.e("TAG", "onError: Status = " + status.toString());
    }
} 

有人可以帮我解决这个问题吗?

感谢任何帮助:)

Screenshot 1

Screenshot 2

Screenshot 3

编辑:此片段是标签式应用的一部分,因此我无法使用活动而非片段。因此,需要在片段中构建mapview和PlaceAutocomplete Widget。我还希望PlaceAutocomplete Widget覆盖地图。我找到了将PlaceAutocomplete Widget放在单独活动中的教程。这不是我要找的解决方案。

1 个答案:

答案 0 :(得分:4)

对于所有遇到相同问题的人,我设法实现了我想要的项目,但是我使用了自定义的AutoCompleteTextView并将其附加到Google Places API。这使我能够创建请求并获得响应。

以下是所有那些希望创建Google PlaceAutoComplete API调用的勇敢灵魂的代码,并覆盖在地图上。

public class GeoFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    GoogleMap map;
    SupportMapFragment mapFragment;
    AutoCompleteTextView destination;
    GooglePlacesAutocompleteAdapter mAdapter;
    ListView listView;
    String dest;

    private LocationRequest lr;
    private GoogleApiClient apiClient;
    private static View view;
    private Location location;
    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
    final String GOOGLE_KEY;

    double currentLatitude;
    double currentLongitude;

    private static final String[] LOCATION_PERMS={
            Manifest.permission.ACCESS_FINE_LOCATION
    };

    public GeoFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        if (!canAccessLocation() || !canAccessLocation()) {
            requestPermissions(LOCATION_PERMS, LOCATION_REQUEST);
        }

        buildGoogleApiClient();

        if (view != null) {
            ViewGroup parent = (ViewGroup) view.getParent();
            if (parent != null)
                parent.removeView(view);
        }

        try {
            view = inflater.inflate(R.layout.layout_map, container, false);

            mapFragment = ((SupportMapFragment) this.getChildFragmentManager().findFragmentById(R.id.mapView));
            destination = (AutoCompleteTextView) view.findViewById(R.id.destinationTextView);

            final CardView destinationCard = (CardView)view.findViewById(R.id._Cardview);
            final CardView placesCard = (CardView)view.findViewById(R.id._cardPlaces);
            mAdapter = new GooglePlacesAutocompleteAdapter(this.getActivity(), android.R.layout.simple_list_item_1);

            listView = (ListView) view.findViewById(R.id.placeList);
            listView.setAdapter(mAdapter);
            listView.setTextFilterEnabled(true);

            destination.addTextChangedListener(new TextWatcher() {

                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    placesCard.setVisibility(View.VISIBLE);
                    mAdapter.getFilter().filter(s.toString());
                }

                @Override
                public void afterTextChanged(Editable s) {
                }
            });

            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                    dest = (String) parent.getItemAtPosition(position);
                    destination.setText(dest);
                    dest = dest.replace(" ", "%20");

                    try {
                        SearchPlace(dest);
                    } catch (GooglePlayServicesNotAvailableException e) {
                        e.printStackTrace();
                    } catch (GooglePlayServicesRepairableException e) {
                        e.printStackTrace();
                    }

                    placesCard.setVisibility(View.INVISIBLE);
                    destinationCard.setVisibility(View.INVISIBLE);
                }
            });

            map = mapFragment.getMap();
            map.getUiSettings().setAllGesturesEnabled(true);
            map.getUiSettings().setMyLocationButtonEnabled(true);
            map.setMyLocationEnabled(true);
            map.getUiSettings().setZoomControlsEnabled(false);

            map.animateCamera(CameraUpdateFactory.zoomIn());
            map.animateCamera(CameraUpdateFactory.zoomTo(15), 2000, null);
            map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(currentLatitude, currentLongitude), 19));

            MapsInitializer.initialize(this.getActivity());
        } catch (InflateException e) {
            Toast.makeText(getActivity(), "Problems inflating the view !",
                    Toast.LENGTH_LONG).show();
        } catch (NullPointerException e) {
            Log.e("GServices Error", e.toString());
        }

        return view;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

        switch(requestCode) {

            case LOCATION_REQUEST:
                if (canAccessLocation()) {
                    callLocationPerms();
                }
                break;
        }
    }

    private void callLocationPerms() {
        Toast.makeText(getActivity().getApplicationContext(),
                "We need your permission to access you current location", Toast.LENGTH_SHORT).show();
    }

    private boolean canAccessLocation() {
        return(hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
    }

    @TargetApi(Build.VERSION_CODES.M)
    private boolean hasPermission(String perm) {
        return(PackageManager.PERMISSION_GRANTED==getActivity().checkSelfPermission(perm));
    }

    protected synchronized void buildGoogleApiClient() {
        apiClient = new GoogleApiClient.Builder(getActivity().getApplicationContext())
                .addApi(LocationServices.API)
                .addApi(Places.GEO_DATA_API)
                .addApi(Places.PLACE_DETECTION_API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }

    private boolean checkPlayServices() {
        int resultCode = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(getActivity().getApplicationContext());
        if (resultCode != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                GooglePlayServicesUtil.getErrorDialog(resultCode, getActivity(), PLAY_SERVICES_RESOLUTION_REQUEST).show();
            }
            return false;
        }
        return true;
    }

    public void getCoordinates(){

        location = LocationServices.FusedLocationApi.getLastLocation(apiClient);

        if (location != null) {
            currentLatitude = location.getLatitude();
            currentLongitude = location.getLongitude();
        }
    }

    @Override
    public void onLocationChanged(Location loc) {

        location = loc;
        getCoordinates();

        map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(currentLatitude, currentLongitude), 19));

    }

    @Override
    public void onConnected(Bundle connectionHint) {

        if (location == null) {
            lr = LocationRequest.create();
            lr.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            lr.setInterval(1000);
            LocationServices.FusedLocationApi.requestLocationUpdates(apiClient, lr, this);

        }
        //getCoordinates();
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        Log.i("Map Connection Failed", "Connection failed: ConnectionResult.getErrorCode() = "
                + result.getErrorCode());
    }

    public void onConnectionSuspended(int arg0) {
        apiClient.connect();
    }

    public void SearchPlace(String place) throws GooglePlayServicesNotAvailableException, GooglePlayServicesRepairableException {
        PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();

        //startActivityForResult(builder.build(getActivity()), PLACE_PICKER_REQUEST);

        callPlaces(currentLongitude, currentLatitude, place);
    }

    public void callPlaces(final double longitude, final double latitude, final String destination) {
        String tag_string_req = "req_places";
        String url =  "https://maps.googleapis.com/maps/api/directions/json?origin=" + latitude + "," + longitude + "&destination="+ destination +"&alternatives=false&mode=transit&region=mt&key=" + getResources().getString(R.string.google_places_key);

        StringRequest strReq = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {

            @Override
            public void onResponse(String response) {
                parsePlace(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("Error", "Registration Error: " + error.getMessage());
                Toast.makeText(getActivity().getApplicationContext(),
                        error.getMessage(), Toast.LENGTH_LONG).show();
            }
        });

        AppController.getInstance().addToRequestQueue(strReq);

    }
}

祝你好运,如果这个答案对你有所帮助,请不要忘记投票:)