我已经实现了Haversine公式来计算当前用户位置与地点之间的距离,但是当我插入代码"http://maps.google.com/maps?saddr=" + gpsHandler.getLatitude() + "," + gpsHandler.getLongitude() + "&daddr=" + endlat + "," + endLng + "&mode=driving"
以用于Google Map Application时,结果还有2至3公里的差距。
第一张图片:Haversine公式结果
第二张图片:Google搜索结果
要获取当前的位置坐标,我分别创建了自己的类处理程序,以便仅在实现hasrsine公式methode的另一个类中调用它。我将给出更清晰的代码。
此GPSHandler.java类可调用当前位置的用户位置
GPSHandler.java
/*
* Copyright 2019 RONINGRUM. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package co.id.roningrum.dolanapptugasakhir.handler;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
/**
* Created by roningrum on 24/06/2019 2019.
*/
public class GPSHandler extends Service implements LocationListener {
private Context context;
private boolean isGPSEnabled = false;
private boolean isNetworkEnabled = false;
private boolean canGetLocation = false;
private Location location;
private double latitude;
private double longitude;
private LocationManager locationManager;
private static final int PERMISSIONS_REQUEST_LOCATION = 99;
private static final long MIN_DISTANCE_CHANGE_UPDATES = 10;
private static final long MIN_TIME_BW_UPDATES = 1000 * 60;
public GPSHandler() {
getLocation();
}
public GPSHandler(Context context) {
this.context = context;
getLocation();
}
@Override
public void onCreate() {
super.onCreate();
getLocation();
}
private Location getLocation() {
try {
locationManager = (LocationManager) context
.getSystemService(LOCATION_SERVICE);
isGPSEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkEnabled = locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled) {
Log.d("Jaringan", "Tidak ada koneksi");
return null;
} else {
checkLocationPermission();
this.canGetLocation = true;
if (isNetworkEnabled) {
locationManager
.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_UPDATES, this);
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(
LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
if (isGPSEnabled) {
locationManager
.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_UPDATES, this);
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(
LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return location;
}
private boolean checkLocationPermission() {
if (ContextCompat.checkSelfPermission(context,
android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions((Activity) context,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_REQUEST_LOCATION);
}
return true;
}
public void stopUsingGPS() {
if (locationManager != null) {
locationManager.removeUpdates(GPSHandler.this);
}
}
public double getLatitude() {
if (location != null) {
latitude = location.getLatitude();
}
return latitude;
}
public double getLongitude() {
if (location != null) {
longitude = location.getLongitude();
}
return longitude;
}
public boolean isCanGetLocation() {
return this.canGetLocation;
}
public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
// Setting Dialog Title
alertDialog.setTitle("GPS is settings");
// Setting Dialog Message
alertDialog
.setMessage("GPS is not enabled. Do you want to go to settings menu?");
// On pressing Settings button
alertDialog.setPositiveButton("Settings",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
context.startActivity(intent);
}
});
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Working", "Service started");
getLocation();
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onLocationChanged(Location location) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
对于使用Haversine公式的计算距离,我在类详细信息活动中插入了显示距离的代码。
BusDetailActivity.java
/*
* Copyright 2019 RONINGRUM. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package co.id.roningrum.dolanapptugasakhir.transportation.bus;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.Objects;
import co.id.roningrum.dolanapptugasakhir.R;
import co.id.roningrum.dolanapptugasakhir.handler.GPSHandler;
import co.id.roningrum.dolanapptugasakhir.item.TransportationItem;
public class BusDetailActivity extends AppCompatActivity implements OnMapReadyCallback {
public static final String EXTRA_BUS_KEY = "busKey";
public static final String MAP_VIEW_KEY = "mapViewBundle";
private final static String TAG = "Pesan";
private GoogleMap busGoogleMap;
private MapView busMapView;
private DatabaseReference busDetailRef;
private GPSHandler gpsHandler;
private ValueEventListener valueEventListener;
private TextView tvNameBusDetail, tvAddressBusDetail, tvDistanceAirport;
private ImageView imgBusDetail;
private CollapsingToolbarLayout collapsingToolbarBus;
private double startLat;
private double startlng;
private double endlat;
private double endLng;
private double distance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bus_detail);
tvNameBusDetail = findViewById(R.id.name_place_bus_detail);
tvAddressBusDetail = findViewById(R.id.address_place_bus_detail);
tvDistanceAirport = findViewById(R.id.distance_place_bus_detail);
collapsingToolbarBus = findViewById(R.id.collapseToolbar_bus);
busMapView = findViewById(R.id.location_bus_map_detail);
imgBusDetail = findViewById(R.id.img_bus_detail);
Toolbar toolbarBus = findViewById(R.id.toolbar_bus_detail);
setSupportActionBar(toolbarBus);
Objects.requireNonNull(getSupportActionBar()).setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAP_VIEW_KEY);
}
busMapView.onCreate(mapViewBundle);
busMapView.getMapAsync(this);
String busKey = getIntent().getStringExtra(EXTRA_BUS_KEY);
if (busKey == null) {
throw new IllegalArgumentException("Must pass Extra");
}
busDetailRef = FirebaseDatabase.getInstance().getReference().child("Transportation").child(busKey);
gpsHandler = new GPSHandler(this);
LoadBusDetail();
}
private void LoadBusDetail() {
if (gpsHandler.isCanGetLocation()) {
ValueEventListener eventListener = new ValueEventListener() {
@SuppressLint("SetTextI18n")
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
final TransportationItem transportationItem = dataSnapshot.getValue(TransportationItem.class);
startLat = gpsHandler.getLatitude();
startlng = gpsHandler.getLongitude();
assert transportationItem != null;
endlat = transportationItem.getLat_transportation();
endLng = transportationItem.getLng_transportation();
distance = calculateDistance(startLat, startlng, endlat, endLng);
@SuppressLint("DefaultLocale") String distanceFormat = String.format("%.2f", distance);
tvDistanceAirport.setText("" + distanceFormat + " km");
tvNameBusDetail.setText(transportationItem.getName_transportation());
tvAddressBusDetail.setText(transportationItem.getLocation_transportation());
Glide.with(getApplicationContext()).load(transportationItem.getUrl_photo_transport()).into(imgBusDetail);
AppBarLayout appBarLayout = findViewById(R.id.app_bar_bus);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.BaseOnOffsetChangedListener() {
boolean isShow = true;
int scrollRange = -1;
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (scrollRange == -1) {
scrollRange = appBarLayout.getTotalScrollRange();
}
if (scrollRange + verticalOffset == 0) {
collapsingToolbarBus.setTitle(transportationItem.getName_transportation());
isShow = true;
} else {
collapsingToolbarBus.setTitle(" ");
isShow = false;
}
}
});
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.e(TAG, "Firebase Database Error" + databaseError.getMessage());
}
};
busDetailRef.addValueEventListener(eventListener);
valueEventListener = eventListener;
}
}
private double calculateDistance(double startLat, double startlng, double endlat, double endLng) {
double earthRadius = 6371;
double latDiff = Math.toRadians(startLat - endlat);
double lngDiff = Math.toRadians(startlng - endLng);
double a = Math.sin(latDiff / 2) * Math.sin(latDiff / 2) +
Math.cos(Math.toRadians(startLat)) * Math.cos(Math.toRadians(endlat)) *
Math.sin(lngDiff / 2) * Math.sin(lngDiff / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = earthRadius * c;
int meterConversion = 1609;
return (distance * meterConversion / 1000);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bundle mapViewBundle = outState.getBundle(MAP_VIEW_KEY);
if (mapViewBundle == null) {
mapViewBundle = new Bundle();
outState.putBundle(MAP_VIEW_KEY, mapViewBundle);
busMapView.onSaveInstanceState(mapViewBundle);
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
busGoogleMap = googleMap;
if (gpsHandler.isCanGetLocation()) {
ValueEventListener eventListener = new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
TransportationItem transportationItem = dataSnapshot.getValue(TransportationItem.class);
assert transportationItem != null;
endlat = transportationItem.getLat_transportation();
endLng = transportationItem.getLng_transportation();
LatLng location = new LatLng(endlat, endLng);
busGoogleMap.addMarker(new MarkerOptions().position(location));
busGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 16.0f));
busGoogleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng latLng) {
String uri = "http://maps.google.com/maps?saddr=" + gpsHandler.getLatitude() + "," + gpsHandler.getLongitude() + "&daddr=" + endlat + "," + endLng + "&mode=driving";
Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(Intent.createChooser(intent, "Select an application"));
}
});
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.e(TAG, "Firebase Database Error" + databaseError.getMessage());
}
};
busDetailRef.addValueEventListener(eventListener);
valueEventListener = eventListener;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Respond to the action bar's Up/Home button
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
busMapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
LoadBusDetail();
busMapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
busMapView.onStop();
busDetailRef.removeEventListener(valueEventListener);
}
@Override
protected void onPause() {
super.onPause();
busMapView.onPause();
}
}
对于数据endLat和endLng,我从Firebase中的数据库中获取了数据
我想显示与Google结果相距0.1 km的准确结果距离。如果您能更好地解决我的问题,我将不胜感激