I refer to https://www.kodetr.com/menentukan-rute-terdekat-dari-lokasi-menggunakan-google-map/
No data in My route class and JSON
It only works show current loction
In Mapsactivity, For(Route route:routes) loop is not work in onDirectionFinderSuccess and no data in routes
Also in DirectionFinder.java, for (int i = 0; i < jsonRoutes.length(); i++) jsonRoutes.length return 0
//XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="574dp"
android:layout_weight="1">
<fragment
android:id="@+id/map"
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"></fragment>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="43dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:background="@android:color/white">
<fragment
android:id="@+id/place_autocomplete_fragment"
android:name="com.google.android.libraries.places.compat.ui.PlaceAutocompleteFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"></fragment>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="25dp"
android:orientation="vertical"
android:padding="5dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="130dp"
android:layout_height="40dp"
android:src="@drawable/distance" />
<TextView
android:id="@+id/tvDistance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="44dp"
android:layout_marginTop="10dp"
android:fontFamily="@font/applesdgothicneom"
android:text="0 km" />
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="130dp"
android:layout_height="40dp"
android:src="@drawable/time" />
<TextView
android:id="@+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="44dp"
android:layout_marginTop="10dp"
android:fontFamily="@font/applesdgothicneom"
android:text="0 mins" />
</RelativeLayout>
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fbsatelit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:layout_marginRight="13dp"
android:layout_marginBottom="156dp"
android:backgroundTint="@android:color/white"
android:backgroundTintMode="screen"
android:src="@drawable/ic_satellite_on" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fbgps"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/fbsatelit"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:layout_marginRight="13dp"
android:layout_marginBottom="84dp"
android:backgroundTint="@android:color/white"
android:backgroundTintMode="screen"
android:src="@drawable/ic_my_gps" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fblocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/fbgps"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|right"
android:layout_marginStart="15dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="15dp"
android:layout_marginRight="14dp"
android:layout_marginBottom="11dp"
android:backgroundTintMode="screen"
android:src="@drawable/ic_directions" />
</RelativeLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
//MapsActivity
public class MapsActivity extends AppCompatActivity implements GoogleMap.OnMarkerClickListener, GoogleMap.OnMapClickListener,OnMapReadyCallback, DirectionFinderListener {
private static final String TAG = MapsActivity.class.getSimpleName();
private LatLng LocationA = new LatLng(37.56, 126.97);
private static final float DEFAULT_ZOOM = 9.5f;
private static final long UPDATE_INTERVAL = 500;
private static final long FASTEST_UPDATE_INTERVAL = UPDATE_INTERVAL / 5;
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
private static boolean gpsFirstOn = true;
private GoogleMap map;
private FusedLocationProviderClient fusedLocationProvider;
private LocationRequest locationRequest;
private LocationCallback locationCallback;
private Location locationgps;
private ResultReceiver resultReceiver;
private Marker selectedMarker;
private LatLng searchLocation;
private List<Marker> originMarkers = new ArrayList<>();
private List<Marker> destinationMarker = new ArrayList<>();
private List<Polyline> polyLinePaths = new ArrayList<>();
private ProgressDialog progressDialog;
@SuppressLint("SetTextI18n")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkLocationPermission();
}
if (!Connections.checkConnection(this)) {
Toast.makeText(this, "네트워크 오류", Toast.LENGTH_SHORT).show();
finish();
}
init();
fusedLocationProvider = LocationServices.getFusedLocationProviderClient(this);
resultReceiver = new ResultReceiver(new Handler()) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
String addressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
Toast.makeText(getApplicationContext(), addressOutput, Toast.LENGTH_SHORT).show();
}
};
locationgps = new Location("Point A");
}
@SuppressLint("SetTextI18n")
private void init() {
setupAutoCompleteFragment();
FloatingActionButton fa = findViewById(R.id.fblocation);
fa.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String origin = locationgps.getLatitude() + "," + locationgps.getLongitude();
try {
new DirectionFinder(MapsActivity.this, origin, searchLocation.latitude + "," + searchLocation.longitude).execute();
}catch (Exception e){e.printStackTrace();}
}
});
final FloatingActionButton ft = findViewById(R.id.fbsatelit);
ft.setOnClickListener(view -> {
if (map != null) {
int MapType = map.getMapType();
if (MapType == 1) {
ft.setImageResource(R.drawable.ic_satellite_off);
map.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
} else {
ft.setImageResource(R.drawable.ic_satellite_on);
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
}
}
});
FloatingActionButton fm = findViewById(R.id.fbgps);
fm.setOnClickListener(view -> {
getDeviceLocation(true);
if (!Geocoder.isPresent()) {
showSnackbar(R.string.no_geocoder_available, Snackbar.LENGTH_LONG, 0, null);
} else {
showAddress();
setCurrentLocation(locationgps);
}
});
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null)
return;
for (Location locationUpdate : locationResult.getLocations()) {
locationgps = locationUpdate;
if (gpsFirstOn) {
gpsFirstOn = false;
getDeviceLocation(true);
}
}
}
};
locationRequest = new LocationRequest();
locationRequest.setInterval(UPDATE_INTERVAL);
locationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
private void setupAutoCompleteFragment() {
PlaceAutocompleteFragment autocompleteFragment = (PlaceAutocompleteFragment)
getFragmentManager().findFragmentById(R.id.place_autocomplete_fragment);
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
@Override
public void onPlaceSelected(Place place) {
searchLocation = place.getLatLng();
}
@Override
public void onError(Status status) {
Log.e("Error", status.getStatusMessage());
}
});
}
public void setCurrentLocation(Location location) {
LatLng currentLatLng = new LatLng(location.getLatitude(), location.getLongitude());
map.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, DEFAULT_ZOOM));
}
@Override
public void onMapReady(GoogleMap gMap) {
map = gMap;
map.setOnMapClickListener(this);
map.setOnMarkerClickListener(this);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(LocationA, DEFAULT_ZOOM));//05.27
map.getUiSettings().setMapToolbarEnabled(false);
map.getUiSettings().setMyLocationButtonEnabled(false);
// TODO : location
map.getProjection().getVisibleRegion();
if (!checkPermission())
requestPermission();
map.setMyLocationEnabled(true);//05.27
}
@Override
public void onDirectionFinderStart() {
progressDialog = ProgressDialog.show(this, "잠시만요", "가장 가까운 위치를 찾고 있습니다", true);
if (originMarkers != null) {
for (Marker marker : originMarkers) {
marker.remove();
}
}
if (destinationMarker != null) {
for (Marker marker : destinationMarker) {
marker.remove();
}
}
if (polyLinePaths != null) {
for (Polyline polylinePath : polyLinePaths) {
polylinePath.remove();
}
}
}
@Override
public void onDirectionFinderSuccess(List<Route> routes) {
progressDialog.dismiss();
polyLinePaths = new ArrayList<>();
originMarkers = new ArrayList<>();
destinationMarker = new ArrayList<>();
for (Route route : routes) {
map.moveCamera(CameraUpdateFactory.newLatLngZoom(route.startLocation, 15.5f));
((TextView) findViewById(R.id.tvDistance)).setText(route.distance.text);
((TextView) findViewById(R.id.tvTime)).setText(route.duration.text);
destinationMarker.add(map.addMarker(new MarkerOptions()
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
.title(route.endAddress)
.position(route.endLocation)));
PolylineOptions polylineOptions = new PolylineOptions()
.geodesic(true)
.color(getResources().getColor(R.color.purple_200))
.width(10);
for (int i = 0; i < route.points.size(); i++) {
polylineOptions.add(route.points.get(i));
}
polyLinePaths.add(map.addPolyline(polylineOptions));
}
}
private void getDeviceLocation(final boolean MyLocation) {
if (!MyLocation)
if (checkPermission()) {
if (map != null)
map.setMyLocationEnabled(true);
final Task<Location> locationResult = fusedLocationProvider.getLastLocation();
locationResult.addOnCompleteListener(this, task -> {
if (task.isSuccessful() && task.getResult() != null) {
// lastKnownLocation = task.getResult();
} else {
Log.w(TAG, "getLastLocation:exception", task.getException());
showSnackbar(R.string.no_location_detected, Snackbar.LENGTH_LONG, 0, null);
}
});
} else // !checkPermission()
Log.d(TAG, "Current location is null. Permission Denied.");
}
@Override
public void onMapClick(final LatLng point) {
selectedMarker = null;
}
@Override
public boolean onMarkerClick(Marker marker) {
if (marker.equals(selectedMarker)) {
selectedMarker = null;
return true;
}
Toast.makeText(this, marker.getTitle(), Toast.LENGTH_SHORT).show();
selectedMarker = marker;
return false;
}
private void showAddress() {
Intent intent = new Intent(this, FetchAddressIntentService.class);
intent.putExtra(Constants.RECEIVER, resultReceiver);
intent.putExtra(Constants.LOCATION_DATA_EXTRA, locationgps);
startService(intent);
}
@Override
protected void onStart() {
super.onStart();
if (Connections.checkConnection(this)) {
new PermissionGPS(this);
}
}
@Override
protected void onRestart() {
super.onRestart();
if (Connections.checkConnection(this)) {
new PermissionGPS(this);
}
}
@Override
protected void onResume() {
super.onResume();
if (Connections.checkConnection(this)) {
if (checkPermission())
fusedLocationProvider.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.i(TAG, "onRequestPermissionResult");
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
if (grantResults.length <= 0)
Log.i(TAG, "User interaction was cancelled.");
else // grantResults.length > 0
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
getDeviceLocation(false);
else
showSnackbar(R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE, android.R.string.ok,
view -> requestPermission());
}
}
private void showSnackbar(int textStringId, int length, int actionStringId, View.OnClickListener listener) {
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), textStringId, length);
if (listener != null)
snackbar.setAction(actionStringId, listener);
snackbar.show();
}
private void requestPermission() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
}
private boolean checkPermission() {
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
public boolean checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
}
//DirectionFinder.java
public class DirectionFinder {
private DirectionFinderListener listener;
private String origin;
private String destination;
public static final String google_api_key="OUR_API_KEY";
public DirectionFinder(DirectionFinderListener listener, String origin, String destination) {
this.listener = listener;
this.origin = origin;
this.destination = destination;
}
public void execute() throws UnsupportedEncodingException {
listener.onDirectionFinderStart();
new DownloadRawData().execute(createUrl());
}
private String createUrl() throws UnsupportedEncodingException {
String urlOrigin = URLEncoder.encode(origin, "utf-8");
String urlDestination = URLEncoder.encode(destination, "utf-8");
return Constants.DIRECTION_URL_API + "origin=" + urlOrigin + "&destination=" + urlDestination + "&key=" + google_api_key;
}
@SuppressLint("StaticFieldLeak")
private class DownloadRawData extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
String link = params[0];
try {
URL url = new URL(link);
InputStream is = url.openConnection().getInputStream();
StringBuilder buffer = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line+"\n");
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String res) {
try {
parseJSon(res);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
private void parseJSon(String data) throws JSONException {
if (data == null)
return;
List<Route> routes = new ArrayList<Route>();
JSONObject jsonData = new JSONObject(data);
JSONArray jsonRoutes = jsonData.getJSONArray("routes");
for (int i = 0; i < jsonRoutes.length(); i++) {
JSONObject jsonRoute = jsonRoutes.getJSONObject(i);
Route route = new Route();
JSONObject overview_polylineJson = jsonRoute.getJSONObject("overview_polyline");
JSONArray jsonLegs = jsonRoute.getJSONArray("legs");
JSONObject jsonLeg = jsonLegs.getJSONObject(0);
JSONObject jsonDistance = jsonLeg.getJSONObject("distance");
JSONObject jsonDuration = jsonLeg.getJSONObject("duration");
JSONObject jsonEndLocation = jsonLeg.getJSONObject("end_location");
JSONObject jsonStartLocation = jsonLeg.getJSONObject("start_location");
route.distance = new Distance(jsonDistance.getString("text"), jsonDistance.getInt("value"));
route.duration = new Duration(jsonDuration.getString("text"), jsonDuration.getInt("value"));
route.endAddress = jsonLeg.getString("end_address");
route.startAddress = jsonLeg.getString("start_address");
route.startLocation = new LatLng(jsonStartLocation.getDouble("lat"), jsonStartLocation.getDouble("lng"));
route.endLocation = new LatLng(jsonEndLocation.getDouble("lat"), jsonEndLocation.getDouble("lng"));
route.points = decodePolyLine(overview_polylineJson.getString("points"));
routes.add(route);
}
listener.onDirectionFinderSuccess(routes);
}
private List<LatLng> decodePolyLine(final String poly) {
int len = poly.length();
int index = 0;
List<LatLng> decoded = new ArrayList<>();
int lat = 0;
int lng = 0;
while (index < len) {
int b;
int shift = 0;
int result = 0;
do {
b = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = poly.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
decoded.add(new LatLng(lat / 100000d, lng / 100000d));
}
return decoded;
}
}
//Route class
public class Route {
public Distance distance;
public Duration duration;
public String endAddress;
public LatLng endLocation;
public String startAddress;
public LatLng startLocation;
public List<LatLng> points;}
//result
{
"geocoded_waypoints" : [ {}, {} ],
"routes" : [],
"status" : "ZERO_RESULTS"
}
It doesn't work when I cliked destination!