在 MapView 片段上放置自动完成小部件

PlaceAutocomplete Widget on MapView Fragment

我正在尝试创建一个地图视图,上面覆盖了 PlaceAutocomplete 小部件。 此视图的功能是计算从我当前位置到我在 PlaceAutocomplete 小部件中选择的位置的距离。

为了更好地解释我自己,我需要一个类似的片段,至于 Google 地图应用程序。目前我已经创建了一个显示地图的片段。这个视图然后被 PlaceAutocomplete 小部件覆盖。

目前,我可以在启动地图视图时获取当前位置。 (屏幕截图 1)然而,当我尝试搜索目的地时(屏幕截图 2),小部件只显示我选择的目的地,而没有调用 Google 路线 API 来获取从我所在位置出发的巴士路线到目的地。 (屏幕截图 3)

从我的 logcat 中,我可以看到构造 URL 和调用 Google 方向 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());
    }
} 

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

感谢任何帮助:)

编辑: 此片段是选项卡式应用程序的一部分,因此我不能使用 activity 代替片段。因此需要在fragment中构建mapview和PlaceAutocomplete Widget。我还想让 PlaceAutocomplete Widget 覆盖地图。我在单独的 activity 中找到了具有 PlaceAutocomplete 小部件的教程。这不是我要找的解决方案。

对于所有遇到同样问题的人,我已经设法实现了我想要的项目,但是我使用了自定义 AutoCompleteTextView 并将其附加到 Google 位置 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);

    }
}

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