![]() |
Figure 1 |
This tutorial will showing something like that. Like Figure 1, you can see how long the distance and duration to the destination. Also you can see which route that recommend by Google Maps
From the Video, is this similar as what you're looking for? If yes, please kindly follow the next steps. But if not, it's also ok for me :D
PREPARATION
1. Get the API KEY from Google
2. Start Development with Android Studio
IMPLEMENTATION
2. Get the KEY and activating the Google Maps API
Open this link : https://developers.google.com/maps/documentation/android-api/ , After in, click the GET API button at the top right side. Take a look at Figure 2
![]() |
Figure 2 |
Next, create new project. The name of the project must be similar with your project in Android Studio. But it's up to you! It's ok. Take a look at Figure 3
![]() |
Figure 3 |
Choose +Create a new project, Fill the project name and press button ENALBE API. After your press the button enable api, you'll given a Server Key. This Server Key that will you use and set in your AndroidManifest. Take a look Figure 4
![]() |
Figure 4 |
As you can see ad Figure 4, you have got the API KEY. You also can open the console by press the button GO TO CONSOLE. Take a look at Figure 5
![]() |
Figure 5 |
You can change the name. Write whatever so make you easy to remember. Because next when you have much project, you'll confusing haha. private experience.
2. Start Development in Android Studio
Before start, the first thing you have to know is the endpoint and the json format. It makes you easy to create the model class. You can check the json format here :
https://maps.googleapis.com/maps/api/directions/json?origin=-8.60815684,115.18285993&destination=-8.1246437,115.3133908&sensor=false&mode=driving&alternatives=true
Several term inside the model that you'll create must be same as the attribute name of the respon json above.
Ok, let's start. In order you don't get confuse while following this tutorial, for a while, please kindly follow my project structure. Take a look at Figure 6
![]() |
Figure 6 |
Let start create the class one by one. First give some permissions on your AndroidManifest.xml and declare the API-KEY-SERVER that we have got.
Second, compile several libraries in your build.gradle (Module:app) that we'll use in this project. Look at the code below :
PACKAGE MODELS
There are some models that we'll use in this tutorial, the function of there method is to do getter and setter. Let's create one by one.
Data.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.models; | |
import com.google.gson.annotations.SerializedName; | |
/** | |
* Created by putuguna on 5/23/2016. | |
*/ | |
public class Data { | |
private String latitude; | |
private String longitude; | |
@SerializedName("created_at") | |
private String modified; | |
@SerializedName("legs") | |
private Legs legs; | |
public Legs getLegs() { | |
return legs; | |
} | |
public void setLegs(Legs legs) { | |
this.legs = legs; | |
} | |
public Data() { | |
} | |
public String getLatitude() { | |
return latitude; | |
} | |
public void setLatitude(String latitude) { | |
this.latitude = latitude; | |
} | |
public String getLongitude() { | |
return longitude; | |
} | |
public void setLongitude(String longitude) { | |
this.longitude = longitude; | |
} | |
public String getModified() { | |
return modified; | |
} | |
public void setModified(String modified) { | |
this.modified = modified; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.models; | |
import com.google.gson.annotations.SerializedName; | |
/** | |
* Created by putuguna on 10/2/2015. | |
*/ | |
public class Legs { | |
@SerializedName("distance") | |
private Distance distance; | |
@SerializedName("duration") | |
private Duration duration; | |
@SerializedName("end_address") | |
private String end_address; | |
@SerializedName("end_location") | |
private EndLocation end_location; | |
@SerializedName("start_address") | |
private String start_address; | |
@SerializedName("start_location") | |
private StartLocation start_location; | |
public Distance getDistance() { | |
return distance; | |
} | |
public void setDistance(Distance distance) { | |
this.distance = distance; | |
} | |
public Duration getDuration() { | |
return duration; | |
} | |
public void setDuration(Duration duration) { | |
this.duration = duration; | |
} | |
public String getEnd_address() { | |
return end_address; | |
} | |
public void setEnd_address(String end_address) { | |
this.end_address = end_address; | |
} | |
public EndLocation getEnd_location() { | |
return end_location; | |
} | |
public void setEnd_location(EndLocation end_location) { | |
this.end_location = end_location; | |
} | |
public String getStart_address() { | |
return start_address; | |
} | |
public void setStart_address(String start_address) { | |
this.start_address = start_address; | |
} | |
public StartLocation getStart_location() { | |
return start_location; | |
} | |
public void setStart_location(StartLocation start_location) { | |
this.start_location = start_location; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.models; | |
/** | |
* Created by putuguna on 5/23/2016. | |
*/ | |
public class Distance { | |
private String text; | |
private String value; | |
public Distance(String text, String value) { | |
this.text = text; | |
this.value = value; | |
} | |
public String getText() { | |
return text; | |
} | |
public String getValue() { | |
return value; | |
} | |
public void setText(String text) { | |
this.text = text; | |
} | |
public void setValue(String value) { | |
this.value = value; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.models; | |
/** | |
* Created by putuguna on 5/23/2016. | |
*/ | |
public class Duration { | |
private String text; | |
private String value; | |
public String getText() { | |
return text; | |
} | |
public String getValue() { | |
return value; | |
} | |
public void setText(String text) { | |
this.text = text; | |
} | |
public void setValue(String value) { | |
this.value = value; | |
} | |
} |
This class used to take route's data from json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.models; | |
import com.google.gson.annotations.SerializedName; | |
import java.util.List; | |
/** | |
* Created by putuguna on 5/23/2016. | |
*/ | |
public class DirectionResultsModel { | |
@SerializedName("routes") | |
private List<Route> routes; | |
public List<Route> getRoutes() { | |
return routes; | |
} | |
public void setRoutes(List<Route> routes) { | |
this.routes = routes; | |
} | |
} |
This class used to take LatLng from the Destination (End Location)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.models; | |
import com.google.gson.annotations.SerializedName; | |
/** | |
* Created by putuguna on 5/23/2016. | |
*/ | |
public class EndLocation { | |
@SerializedName("lat") | |
private String lat; | |
@SerializedName("lng") | |
private String lng; | |
public String getLat() { | |
return lat; | |
} | |
public void setLat(String lat) { | |
this.lat = lat; | |
} | |
public String getLng() { | |
return lng; | |
} | |
public void setLng(String lng) { | |
this.lng = lng; | |
} | |
} |
This class used to take all of Leg's data from json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.models; | |
import com.google.gson.annotations.SerializedName; | |
import java.util.List; | |
/** | |
* Created by putuguna on 5/23/2016. | |
*/ | |
public class Route { | |
@SerializedName("legs") | |
private List<Legs> legs; | |
public List<Legs> getLegs() { | |
return legs; | |
} | |
public void setLegs(List<Legs> legs) { | |
this.legs = legs; | |
} | |
} |
This class used ti take LatLng's data from Origin (Start Location)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.models; | |
import com.google.gson.annotations.SerializedName; | |
/** | |
* Created by putuguna on 5/23/2016. | |
*/ | |
public class StartLocation { | |
@SerializedName("lat") | |
private String lat; | |
@SerializedName("lng") | |
private String lng; | |
public String getLat() { | |
return lat; | |
} | |
public void setLat(String lat) { | |
this.lat = lat; | |
} | |
public String getLng() { | |
return lng; | |
} | |
public void setLng(String lng) { | |
this.lng = lng; | |
} | |
} |
PACKAGE HELPERS
In this package contains several class.java that used to make easy development proccess
Constant.java
This class contains variables that used as key in storing data in SharedPreference and Storing URL/Endpoint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.helpers; | |
/** | |
* Created by putuguna on 5/14/2016. | |
*/ | |
public class Constant { | |
public static final String CURRENT_LAT = "current-lat"; | |
public static final String CURRENT_LONG = "current-long"; | |
public static final String GOOGLE_END_POINT = "https://maps.googleapis.com/"; | |
public static final String GOOGLE_DIRECTION = "https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&key="; | |
public static final String LAT_CHOSEN = "lat-chosen"; | |
public static final String LONG_CHOSEN = "long-chosen"; | |
public static final String NAME_CHOSEN = "name-chosen"; | |
public static final String DURATION_CHOSEN = "dur-chosen"; | |
public static final String DISTANCE_CHOSEN = "dis-chosen"; | |
} |
This class used to parse JSON. In this class also contains method that create polyline
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.helpers; | |
import com.google.android.gms.maps.model.LatLng; | |
import org.json.JSONArray; | |
import org.json.JSONException; | |
import org.json.JSONObject; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
/** | |
* Created by putuguna on 5/22/2016. | |
*/ | |
public class DirectionsJSONParser { | |
/** | |
* Receives a JSONObject and returns a list of lists containing latitude and longitude | |
*/ | |
public List<List<HashMap<String, String>>> parse(JSONObject jObject) { | |
List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>(); | |
JSONArray jRoutes = null; | |
JSONArray jLegs = null; | |
JSONArray jSteps = null; | |
try { | |
jRoutes = jObject.getJSONArray("routes"); | |
/** Traversing all routes */ | |
for (int i = 0; i < jRoutes.length(); i++) { | |
jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs"); | |
List path = new ArrayList<HashMap<String, String>>(); | |
/** Traversing all legs */ | |
for (int j = 0; j < jLegs.length(); j++) { | |
jSteps = ((JSONObject) jLegs.get(j)).getJSONArray("steps"); | |
/** Traversing all steps */ | |
for (int k = 0; k < jSteps.length(); k++) { | |
String polyline = ""; | |
polyline = (String) ((JSONObject) ((JSONObject) jSteps.get(k)).get("polyline")).get("points"); | |
List<LatLng> list = decodePoly(polyline); | |
/** Traversing all points */ | |
for (int l = 0; l < list.size(); l++) { | |
HashMap<String, String> hm = new HashMap<String, String>(); | |
hm.put("lat", Double.toString(((LatLng) list.get(l)).latitude)); | |
hm.put("lng", Double.toString(((LatLng) list.get(l)).longitude)); | |
path.add(hm); | |
} | |
} | |
routes.add(path); | |
} | |
} | |
} catch (JSONException e) { | |
e.printStackTrace(); | |
} catch (Exception e) { | |
} | |
return routes; | |
} | |
/** | |
* Method to decode polyline points | |
* Courtesy : jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java | |
*/ | |
private List<LatLng> decodePoly(String encoded) { | |
List<LatLng> poly = new ArrayList<LatLng>(); | |
int index = 0, len = encoded.length(); | |
int lat = 0, lng = 0; | |
while (index < len) { | |
int b, shift = 0, result = 0; | |
do { | |
b = encoded.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 = encoded.charAt(index++) - 63; | |
result |= (b & 0x1f) << shift; | |
shift += 5; | |
} while (b >= 0x20); | |
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); | |
lng += dlng; | |
LatLng p = new LatLng((((double) lat / 1E5)), | |
(((double) lng / 1E5))); | |
poly.add(p); | |
} | |
return poly; | |
} | |
} |
As previous tutorials, class LoggingInterceptor used to make easy for debugging
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.helpers; | |
import android.util.Log; | |
import com.squareup.okhttp.Interceptor; | |
import com.squareup.okhttp.Request; | |
import com.squareup.okhttp.Response; | |
import com.squareup.okhttp.ResponseBody; | |
import java.io.IOException; | |
import okio.Buffer; | |
/** | |
* Created by putuguna on 1/27/2016. | |
*/ | |
public class LoggingInterceptorGoogle implements Interceptor { | |
@Override | |
public Response intercept(Chain chain) throws IOException { | |
Request request = chain.request(); | |
long t1 = System.nanoTime(); | |
String requestLog = String.format("Sending request %s on %s%n%s", | |
request.url(), chain.connection(), request.headers()); | |
//YLog.d(String.format("Sending request %s on %s%n%s", | |
// request.url(), chain.connection(), request.headers())); | |
if (request.method().compareToIgnoreCase("post") == 0) { | |
requestLog = "\n" + requestLog + "\n" + bodyToString(request); | |
} | |
Log.d("TAG", "request" + "\n" + requestLog); | |
Response response = chain.proceed(request); | |
long t2 = System.nanoTime(); | |
String responseLog = String.format("Received response for %s in %.1fms%n%s", | |
response.request().url(), (t2 - t1) / 1e6d, response.headers()); | |
String bodyString = response.body().string(); | |
Log.d("TAG", "response" + "\n" + responseLog + "\n" + bodyString); | |
return response.newBuilder() | |
.body(ResponseBody.create(response.body().contentType(), bodyString)) | |
.build(); | |
} | |
public static String bodyToString(final Request request) { | |
try { | |
final Request copy = request.newBuilder().build(); | |
final Buffer buffer = new Buffer(); | |
copy.body().writeTo(buffer); | |
return buffer.readUtf8(); | |
} catch (final IOException e) { | |
return "did not work"; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putuguna.com.mapsnomatrix; | |
import android.content.Context; | |
import android.content.SharedPreferences; | |
import android.preference.PreferenceManager; | |
/** | |
* Created by putuguna on 5/14/2016. | |
*/ | |
public class Utils { | |
public static String getStrings(Context ctx, String key) { | |
SharedPreferences sharedPreferences = PreferenceManager | |
.getDefaultSharedPreferences(ctx); | |
String value = sharedPreferences.getString( | |
key, null); | |
return value; | |
} | |
//save string | |
public static void saveString(Context context, String key, String value){ | |
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); | |
SharedPreferences.Editor edit = sharedPreferences.edit(); | |
edit.putString(key, value); | |
edit.commit(); | |
} | |
} |
PACKAGE APISERVICES
In this package contains an interface. This interface contains method that i used to execute the URL/Endpoint that has been prepared
ApiService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putuguna.com.mapsnomatrix; | |
import retrofit.Call; | |
import retrofit.http.GET; | |
import retrofit.http.Query; | |
/** | |
* Created by putuguna on 1/27/2016. | |
*/ | |
public interface ApiService { | |
/* @GET("api/gateways") | |
public Call<DataResponse> getAllData(); | |
@GET("api/gateways") | |
public Call<DataResponse> getListData(@Query("api_key") String api_key);*/ | |
@GET("/maps/api/distancematrix/json") | |
public Call<Data> getDirection(@Query("origin") String origin, @Query("destination") String destination); | |
@GET("/maps/api/directions/json") | |
public Call<DirectionResultsModel> getDistanceAndDuration(@Query("origin") String origin, @Query("destination") String destination, @Query("sensor") String sensor, @Query("mode") String mode, @Query("alternatives") String alternatives); | |
} |
PACKAGE ADAPTER
In this package only contains adapter class. The function of this adapter is set and show list object location
AdapterListView.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putuguna.com.mapsnomatrix.adapter; | |
import android.content.Context; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.ArrayAdapter; | |
import android.widget.TextView; | |
import java.util.ArrayList; | |
import java.util.List; | |
import putuguna.com.mapsnomatrix.Data; | |
import putuguna.com.mapsnomatrix.R; | |
/** | |
* Created by gunaputu on 20/10/2015. | |
*/ | |
public class AdapterListVIew extends ArrayAdapter<Data> { | |
private Context context; | |
int layoutResourceId; | |
private List<Data> listData; | |
private List<String> list; | |
LayoutInflater inflater; | |
private ArrayList<Data> arraylist; | |
public AdapterListVIew(Context context, int layoutResourceId, List<Data> listData, List<String> list) { | |
super(context, layoutResourceId, listData); | |
this.list= list; | |
this.context = context; | |
this.layoutResourceId = layoutResourceId; | |
this.listData = listData; | |
inflater = LayoutInflater.from(context); | |
this.arraylist = new ArrayList<>(); | |
this.arraylist.addAll(listData); | |
} | |
public AdapterListVIew(Context context, int layoutResourceId, List<Data> listData) { | |
super(context, layoutResourceId, listData); | |
this.context = context; | |
this.layoutResourceId = layoutResourceId; | |
this.listData = listData; | |
inflater = LayoutInflater.from(context); | |
this.arraylist = new ArrayList<>(); | |
this.arraylist.addAll(listData); | |
} | |
public View getView(int position,View view,ViewGroup parent){ | |
Data datas = listData.get(position); | |
Holder holder ; | |
if(view == null){ | |
holder =new Holder(); | |
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); | |
view = inflater.inflate(R.layout.row_item_data,parent, false); | |
holder.name = (TextView) view.findViewById(R.id.name_of_data); | |
holder.distance = (TextView) view.findViewById(R.id.distance); | |
holder.duration = (TextView) view.findViewById(R.id.duration); | |
holder.latitude = (TextView) view.findViewById(R.id.latitude); | |
holder.longitude = (TextView) view.findViewById(R.id.longitude); | |
view.setTag(holder); | |
} else { | |
holder = (Holder) view.getTag(); | |
} | |
holder.name.setText(datas.getModified()); | |
holder.duration.setText("Duration from current position, it's about " + datas.getLegs().getDuration().getText()); | |
holder.distance.setText("from current position, it's about " + datas.getLegs().getDistance().getText()); | |
holder.latitude.setText("Latitude : " + datas.getLatitude()); | |
holder.longitude.setText("Longitude : " + datas.getLongitude()); | |
return view; | |
} | |
static class Holder{ | |
private TextView name; | |
private TextView distance; | |
private TextView duration; | |
private TextView latitude; | |
private TextView longitude; | |
} | |
@Override | |
public Data getItem(int position) { | |
if(this.listData != null) { | |
this.list.get(position); | |
} else { | |
return null; | |
} | |
return null; | |
} | |
//Filter for mSearch function | |
/* public void filter(String charText) { | |
charText = charText.toLowerCase(Locale.getDefault()); | |
listData.clear(); | |
if (charText.length() == 0) { | |
listData.addAll(arraylist); | |
} else { | |
for (int i=0; i<listData.size(); i++) { | |
if (listData.get(i).getName().toLowerCase(Locale.getDefault()) | |
.contains(charText)) { | |
listData.add(listData.get(i)); | |
} | |
} | |
} | |
notifyDataSetChanged(); | |
}*/ | |
} |
PACKAGE ACTIVITIES
In this package contains only Activity classes
ListDestinationActivity.java
This class used to show all the destination list. Later, when we choose one location from the list, it will direct to the maps and show the route between origin and destination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.activities; | |
import android.annotation.TargetApi; | |
import android.app.ProgressDialog; | |
import android.content.Intent; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.support.v7.app.AppCompatActivity; | |
import android.view.MenuItem; | |
import android.view.View; | |
import android.widget.AdapterView; | |
import android.widget.ListView; | |
import java.util.Comparator; | |
import java.util.List; | |
import putugunation.com.mapsroute.R; | |
import putugunation.com.mapsroute.adapters.AdapterListVIew; | |
import putugunation.com.mapsroute.helpers.Constant; | |
import putugunation.com.mapsroute.helpers.Utils; | |
import putugunation.com.mapsroute.models.Data; | |
public class ListDestinationActivity extends AppCompatActivity { | |
private ListView listView; | |
private AdapterListVIew adapter; | |
private List<Data> listData; | |
private ProgressDialog progressDialog; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main2); | |
listView = (ListView) findViewById(R.id.recyclerView_data); | |
getSupportActionBar().setDisplayHomeAsUpEnabled(true); | |
progressDialog = new ProgressDialog(this); | |
setListAdapter(MainActivity.data); | |
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
@Override | |
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | |
Intent intents = new Intent(ListDestinationActivity.this, ViewRouteActivity.class); | |
startActivity(intents); | |
Utils.saveString(ListDestinationActivity.this, Constant.LAT_CHOSEN, MainActivity.data.get(position).getLatitude()); | |
Utils.saveString(ListDestinationActivity.this, Constant.LONG_CHOSEN, MainActivity.data.get(position).getLongitude()); | |
Utils.saveString(ListDestinationActivity.this,Constant.NAME_CHOSEN, MainActivity.data.get(position).getModified()); | |
Utils.saveString(ListDestinationActivity.this,Constant.DURATION_CHOSEN, MainActivity.data.get(position).getLegs().getDuration().getText()); | |
Utils.saveString(ListDestinationActivity.this,Constant.DISTANCE_CHOSEN, MainActivity.data.get(position).getLegs().getDistance().getText()); | |
} | |
}); | |
} | |
private void setListAdapter(final List<Data> list){ | |
try { | |
adapter = new AdapterListVIew(ListDestinationActivity.this,R.layout.row_item_data,list); | |
listView.setAdapter(adapter); | |
adapter.sort(new Comparator<Data>() { | |
@TargetApi(Build.VERSION_CODES.KITKAT) | |
@Override | |
public int compare(Data lhs, Data rhs) { | |
int value1 = Integer.parseInt(lhs.getLegs().getDistance().getValue()); | |
int value2 = Integer.parseInt(lhs.getLegs().getDuration().getValue()); | |
return Integer.compare(value1, value2); | |
} | |
}); | |
}catch (Exception e){ | |
e.printStackTrace(); | |
} | |
} | |
@Override | |
public boolean onOptionsItemSelected(MenuItem item) { | |
int id = item.getItemId(); | |
if(id== android.R.id.home){ | |
onBackPressed(); | |
} | |
return super.onOptionsItemSelected(item); | |
} | |
} |
This class will showing the destination, duration and route from the origin to the destination.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.activities; | |
import android.Manifest; | |
import android.app.Dialog; | |
import android.content.pm.PackageManager; | |
import android.graphics.Color; | |
import android.location.Criteria; | |
import android.location.Location; | |
import android.location.LocationListener; | |
import android.location.LocationManager; | |
import android.os.AsyncTask; | |
import android.os.Bundle; | |
import android.support.v4.app.ActivityCompat; | |
import android.support.v4.app.FragmentActivity; | |
import android.util.Log; | |
import android.widget.TextView; | |
import com.google.android.gms.common.ConnectionResult; | |
import com.google.android.gms.common.GooglePlayServicesUtil; | |
import com.google.android.gms.maps.CameraUpdateFactory; | |
import com.google.android.gms.maps.GoogleMap; | |
import com.google.android.gms.maps.MapFragment; | |
import com.google.android.gms.maps.model.BitmapDescriptorFactory; | |
import com.google.android.gms.maps.model.LatLng; | |
import com.google.android.gms.maps.model.MarkerOptions; | |
import com.google.android.gms.maps.model.PolylineOptions; | |
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; | |
import putugunation.com.mapsroute.R; | |
import putugunation.com.mapsroute.helpers.Constant; | |
import putugunation.com.mapsroute.helpers.DirectionsJSONParser; | |
import putugunation.com.mapsroute.helpers.Utils; | |
/** | |
* Created by putuguna on 9/20/2016. | |
*/ | |
public class ViewRouteActivity extends FragmentActivity implements LocationListener { | |
private GoogleMap mGoogleMap; | |
private double mLatitude = 0; | |
private double mLongitude = 0; | |
private double latChosen; | |
private double longChosen; | |
private String namePlace; | |
private String duration; | |
private String distance; | |
private TextView detail; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_view_route); | |
detail = (TextView) findViewById(R.id.detail); | |
latChosen = Double.parseDouble(Utils.getStrings(this, Constant.LAT_CHOSEN)); | |
longChosen = Double.parseDouble(Utils.getStrings(this, Constant.LONG_CHOSEN)); | |
namePlace = Utils.getStrings(this, Constant.NAME_CHOSEN); | |
duration = Utils.getStrings(this, Constant.DURATION_CHOSEN); | |
distance = Utils.getStrings(this, Constant.DISTANCE_CHOSEN); | |
Log.d("TAG", "CHOSEN : " + latChosen + " : " + longChosen); | |
detail.setText("Distance : " + distance + ", Duration : " + duration); | |
// Getting Google Play availability status | |
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext()); | |
if (status != ConnectionResult.SUCCESS) { // Google Play Services are not available | |
int requestCode = 10; | |
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode); | |
dialog.show(); | |
} else { // Google Play Services are available | |
// Getting reference to SupportMapFragment of the activity_main | |
MapFragment fm = (MapFragment) getFragmentManager().findFragmentById(R.id.map_view); | |
// Getting Map for the SupportMapFragment | |
mGoogleMap = fm.getMapAsync(this); | |
// Enable MyLocation Button in the Map | |
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { | |
// TODO: Consider calling | |
// ActivityCompat#requestPermissions | |
// here to request the missing permissions, and then overriding | |
// public void onRequestPermissionsResult(int requestCode, String[] permissions, | |
// int[] grantResults) | |
// to handle the case where the user grants the permission. See the documentation | |
// for ActivityCompat#requestPermissions for more details. | |
return; | |
} | |
mGoogleMap.setMyLocationEnabled(true); | |
// Getting LocationManager object from System Service LOCATION_SERVICE | |
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); | |
// Creating a criteria object to retrieve provider | |
Criteria criteria = new Criteria(); | |
// Getting the name of the best provider | |
String provider = locationManager.getBestProvider(criteria, true); | |
// Getting Current Location From GPS | |
Location location = locationManager.getLastKnownLocation(provider); | |
if(location!=null){ | |
onLocationChanged(location); | |
} | |
locationManager.requestLocationUpdates(provider, 20000, 0, this); | |
LatLng origin = new LatLng(mLatitude, mLongitude); | |
LatLng dest = new LatLng(latChosen, longChosen); | |
// Getting URL to the Google Directions API | |
String url = getDirectionsUrl(origin, dest); | |
DownloadTask downloadTask = new DownloadTask(); | |
// Start downloading json data from Google Directions API | |
downloadTask.execute(url); | |
} | |
// otherMarker(); | |
} | |
@Override | |
public void onLocationChanged(Location location) { | |
// Draw the marker, if destination location is not set | |
mLatitude = location.getLatitude(); | |
mLongitude = location.getLongitude(); | |
LatLng point = new LatLng(mLatitude, mLongitude); | |
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(point)); | |
mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(12)); | |
drawMarker(point); | |
} | |
@Override | |
public void onStatusChanged(String provider, int status, Bundle extras) { | |
} | |
@Override | |
public void onProviderEnabled(String provider) { | |
} | |
@Override | |
public void onProviderDisabled(String provider) { | |
} | |
/** | |
* this method used to get LatLng of origin and destination | |
* @param origin | |
* @param dest | |
* @return | |
*/ | |
private String getDirectionsUrl(LatLng origin,LatLng dest){ | |
// Origin of route | |
String str_origin = "origin="+origin.latitude+","+origin.longitude; | |
// Destination of route | |
String str_dest = "destination="+dest.latitude+","+dest.longitude; | |
// Sensor enabled | |
String sensor = "sensor=false"; | |
// Building the parameters to the web service | |
String parameters = str_origin+"&"+str_dest+"&"+sensor; | |
// Output format | |
String output = "json"; | |
// Building the url to the web service | |
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters; | |
return url; | |
} | |
/** | |
* this method used to download json's data from URL | |
* @param strUrl | |
* @return | |
* @throws IOException | |
*/ | |
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("TAG","Exception while downloading url"+ e.toString()); | |
}finally{ | |
iStream.close(); | |
urlConnection.disconnect(); | |
} | |
return data; | |
} | |
/** A class to download data from Google Directions URL */ | |
private class DownloadTask extends AsyncTask<String,Void,String> { | |
// Downloading data in non-ui thread | |
@Override | |
protected String doInBackground(String... url) { | |
// For storing data from web service | |
String data = ""; | |
try{ | |
// Fetching the data from web service | |
data = downloadUrl(url[0]); | |
}catch(Exception e){ | |
Log.d("Background Task",e.toString()); | |
} | |
return data; | |
} | |
// Executes in UI thread, after the execution of | |
// doInBackground() | |
@Override | |
protected void onPostExecute(String result) { | |
super.onPostExecute(result); | |
ParserTask parserTask = new ParserTask(); | |
// Invokes the thread for parsing the JSON data | |
parserTask.execute(result); | |
} | |
} | |
/** A class to parse the Google Directions in JSON format */ | |
private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String,String>>> >{ | |
// Parsing the data in non-ui thread | |
@Override | |
protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) { | |
JSONObject jObject; | |
List<List<HashMap<String, String>>> routes = null; | |
try{ | |
jObject = new JSONObject(jsonData[0]); | |
DirectionsJSONParser parser = new DirectionsJSONParser(); | |
// Starts parsing data | |
routes = parser.parse(jObject); | |
}catch(Exception e){ | |
e.printStackTrace(); | |
} | |
return routes; | |
} | |
// Executes in UI thread, after the parsing process | |
@Override | |
protected void onPostExecute(List<List<HashMap<String, String>>> result) { | |
ArrayList<LatLng> points = null; | |
PolylineOptions lineOptions = null; | |
// Traversing through all the routes | |
for(int i=0;i<result.size();i++){ | |
points = new ArrayList<LatLng>(); | |
lineOptions = new PolylineOptions(); | |
// Fetching i-th route | |
List<HashMap<String, String>> path = result.get(i); | |
// Fetching all the points in i-th route | |
for(int j=0;j<path.size();j++){ | |
HashMap<String,String> point = path.get(j); | |
double lat = Double.parseDouble(point.get("lat")); | |
double lng = Double.parseDouble(point.get("lng")); | |
LatLng position = new LatLng(lat, lng); | |
points.add(position); | |
} | |
// Adding all the points in the route to LineOptions | |
lineOptions.addAll(points); | |
lineOptions.width(2); | |
lineOptions.color(Color.RED); | |
} | |
// Drawing polyline in the Google Map for the i-th route | |
mGoogleMap.addPolyline(lineOptions); | |
} | |
} | |
/** | |
* this method used to draw a marker from LatLng | |
* @param point | |
*/ | |
private void drawMarker(LatLng point){ | |
// Creating MarkerOptions | |
MarkerOptions options = new MarkerOptions(); | |
options.position(point); | |
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); | |
options.title("Hi You!"); | |
options.snippet("Your Location"); | |
mGoogleMap.addMarker(options).showInfoWindow(); | |
//map others | |
mGoogleMap.addMarker(new MarkerOptions().position(new LatLng(latChosen, longChosen)).title(namePlace).snippet("Your Destination")).showInfoWindow(); | |
} | |
} |
This class will showing the map include the marker from the list location that we have.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package putugunation.com.mapsroute.activities; | |
import android.Manifest; | |
import android.app.ProgressDialog; | |
import android.content.Intent; | |
import android.content.pm.PackageManager; | |
import android.location.Criteria; | |
import android.location.Location; | |
import android.location.LocationListener; | |
import android.location.LocationManager; | |
import android.support.v4.app.ActivityCompat; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
import android.util.Log; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.Toast; | |
import com.google.android.gms.maps.CameraUpdateFactory; | |
import com.google.android.gms.maps.GoogleMap; | |
import com.google.android.gms.maps.MapFragment; | |
import com.google.android.gms.maps.model.CameraPosition; | |
import com.google.android.gms.maps.model.LatLng; | |
import com.google.android.gms.maps.model.MarkerOptions; | |
import com.squareup.okhttp.OkHttpClient; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.concurrent.CountDownLatch; | |
import putugunation.com.mapsroute.R; | |
import putugunation.com.mapsroute.apiservices.ApiService; | |
import putugunation.com.mapsroute.helpers.Constant; | |
import putugunation.com.mapsroute.helpers.LoggingInterceptorGoogle; | |
import putugunation.com.mapsroute.helpers.Utils; | |
import putugunation.com.mapsroute.models.Data; | |
import putugunation.com.mapsroute.models.DirectionResultsModel; | |
import putugunation.com.mapsroute.models.Legs; | |
import retrofit.Call; | |
import retrofit.GsonConverterFactory; | |
import retrofit.Retrofit; | |
public class MainActivity extends AppCompatActivity implements LocationListener{ | |
public static final int REQUEST_CODE_LOCATION = 121; | |
private GoogleMap googleMap; | |
private ApiService serviceGoogleDirection; | |
public static List<Data> data; | |
private LatLng currentPosition; | |
private LocationManager locationManager; | |
private Button buttonCheckList; | |
private ProgressDialog progressDialog; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
buttonCheckList = (Button) findViewById(R.id.buttonCekList); | |
requestPermission(); | |
} | |
/** | |
* Update Juni 2018 | |
* For users that use OS version 7 and 8, it must be crash because the permission of location is denied | |
* Please use code below to fix it. | |
*/ | |
private void requestPermission() { | |
ActivityCompat.requestPermissions(this, | |
new String[]{ | |
Manifest.permission.ACCESS_FINE_LOCATION, | |
Manifest.permission.ACCESS_COARSE_LOCATION | |
}, | |
REQUEST_CODE_LOCATION); | |
} | |
private void setDataListAfterPermissionAllowed(){ | |
//1. initialization your maps | |
//2. set your lat and lang | |
try { | |
initilizeMap(); | |
Data d1 = new Data(); | |
d1.setLatitude(-8.6947 + ""); | |
d1.setLongitude(115.263 + ""); | |
d1.setModified("Sanur Beach"); | |
Data d2 = new Data(); | |
d2.setLatitude(-8.7208 + ""); | |
d2.setLongitude(115.1692 + ""); | |
d2.setModified("Kuta Beach"); | |
Data d3 = new Data(); | |
d3.setLatitude(-8.8 + ""); | |
d3.setLongitude(115.2333 + ""); | |
d3.setModified("Dreamland Beach"); | |
Data d4 = new Data(); | |
d4.setLatitude(-8.8453597 + ""); | |
d4.setLongitude(115.1110346 + ""); | |
d4.setModified("Nyang-Nyang Beach"); | |
Data d5 = new Data(); | |
d5.setLatitude(-8.1246437 + ""); | |
d5.setLongitude(115.3133908 + ""); | |
d5.setModified("Bondalem Village"); | |
List<Data> addata = new ArrayList<>(); | |
addata.add(d1); | |
addata.add(d2); | |
addata.add(d3); | |
addata.add(d4); | |
addata.add(d5); | |
data = addata; | |
setDistanceForAll(data); | |
addMarker(data); | |
}catch (Exception e){e.printStackTrace();} | |
buttonCheckList.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
Intent intent = new Intent(MainActivity.this, ListDestinationActivity.class); | |
startActivity(intent); | |
} | |
}); | |
} | |
@Override | |
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | |
switch (requestCode){ | |
case REQUEST_CODE_LOCATION: | |
if(grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ | |
setDataListAfterPermissionAllowed() | |
}else{ | |
Toast.makeText(this, "Permission denied!. Please enable manualy at menu setting in your device", Toast.LENGTH_SHORT).show(); | |
} | |
} | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
try { | |
initilizeMap(); | |
}catch (Exception e){e.printStackTrace();} | |
} | |
/** | |
* this method used to get direction and duration between 2 LatLng | |
* @param origin | |
* @param destination | |
* @return | |
*/ | |
private Legs getDirectionAndDuration(final LatLng origin, final LatLng destination){ | |
OkHttpClient clientGoogleApi = new OkHttpClient(); | |
clientGoogleApi.interceptors().add(new LoggingInterceptorGoogle()); | |
Retrofit retrofitGoogleApi = new Retrofit.Builder() | |
.baseUrl(Constant.GOOGLE_END_POINT) | |
.client(clientGoogleApi) | |
.addConverterFactory(GsonConverterFactory.create()) | |
.build(); | |
serviceGoogleDirection = retrofitGoogleApi.create(ApiService.class); | |
final Legs[] distanceDurationModel = new Legs[1]; | |
final CountDownLatch latch = new CountDownLatch(1); | |
Thread thread = new Thread(new Runnable() { | |
@Override | |
public void run() { | |
Call<DirectionResultsModel> directionResultsCall; | |
directionResultsCall = serviceGoogleDirection.getDistanceAndDuration(origin.latitude + "," + origin.longitude , destination.latitude + "," + destination.longitude, "false","driving","true"); | |
try { | |
DirectionResultsModel results = directionResultsCall.execute().body(); | |
distanceDurationModel[0] = results.getRoutes().get(0).getLegs().get(0); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
latch.countDown(); | |
} | |
}); | |
thread.start(); | |
try { | |
latch.await(); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
return distanceDurationModel[0]; | |
} | |
/** | |
* this method used to set distance of all Data | |
* @param listData | |
* @return | |
*/ | |
private List<Data> setDistanceForAll(List<Data> listData){ | |
for(Data data : listData){ | |
double destLat = Double.parseDouble(data.getLatitude()); | |
double destLng = Double.parseDouble(data.getLongitude()); | |
LatLng destination = new LatLng(destLat,destLng); | |
Legs legs = getDirectionAndDuration(currentPosition, destination); | |
data.setLegs(legs); | |
Log.d("TAG", "TEST : " + data.getLegs().getDistance().getText()); | |
Log.d("TAG", "TEST : " + data.getLegs().getDuration().getText()); | |
} | |
return listData; | |
} | |
/** | |
* this method used to show a map | |
*/ | |
private void initilizeMap() { | |
if (googleMap == null) { | |
googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.maps)).getMapAsync(this); | |
//check if map created successful or not | |
if (googleMap == null) { | |
Toast.makeText(getApplicationContext(), "Sorry unable to crated map", Toast.LENGTH_SHORT).show(); | |
} | |
} | |
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { | |
// TODO: Consider calling | |
// ActivityCompat#requestPermissions | |
// here to request the missing permissions, and then overriding | |
// public void onRequestPermissionsResult(int requestCode, String[] permissions, | |
// int[] grantResults) | |
// to handle the case where the user grants the permission. See the documentation | |
// for ActivityCompat#requestPermissions for more details. | |
return; | |
} | |
googleMap.setMyLocationEnabled(true); | |
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); | |
Criteria criteria = new Criteria(); | |
String provider = locationManager.getBestProvider(criteria,true); | |
//get current location from gps | |
Location location = locationManager.getLastKnownLocation(provider); | |
if(location!=null){ | |
onLocationChanged(location); | |
} | |
locationManager.requestLocationUpdates(provider,20000,0,this); | |
String latitude = Utils.getStrings(MainActivity.this, Constant.CURRENT_LAT); | |
String longitude = Utils.getStrings(MainActivity.this, Constant.CURRENT_LONG); | |
Toast.makeText(this, "LOKASIKU : " + location.getLongitude(), Toast.LENGTH_SHORT).show(); | |
currentPosition = new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude)); | |
//creating marker | |
MarkerOptions marker = new MarkerOptions().position(new LatLng(Double.parseDouble(Utils.getStrings(this, Constant.CURRENT_LAT)), Double.parseDouble(Utils.getStrings(this,Constant.CURRENT_LONG)))).title("Hi You!").snippet("This is your location"); | |
googleMap.addMarker(marker).showInfoWindow(); | |
// googleMap.addMarker(new MarkerOptions().position(new LatLng(-8.6947, 115.263)).title("Sanur Beach").snippet("One of Sunrise spot")).showInfoWindow(); | |
// googleMap.addMarker(new MarkerOptions().position(new LatLng(-8.7208, 115.1692)).title("Kuta Beach").snippet("One of Sunset spot")).showInfoWindow(); | |
CameraPosition cameraPosition = new CameraPosition.Builder().target(new LatLng(Double.parseDouble(Utils.getStrings(this, Constant.CURRENT_LAT)), Double.parseDouble(Utils.getStrings(this,Constant.CURRENT_LONG)))).zoom(12).build(); | |
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); | |
} | |
/** | |
* this method used to draw a marker using LatLng in List | |
* @param data | |
*/ | |
private void addMarker(List<Data> data){ | |
for(Data d : data){ | |
googleMap.addMarker(new MarkerOptions().position(new LatLng(Double.parseDouble(d.getLatitude()), Double.parseDouble(d.getLongitude()))).title(d.getModified()).snippet("Your Destination")).showInfoWindow(); | |
} | |
} | |
@Override | |
public void onLocationChanged(Location location) { | |
Utils.saveString(MainActivity.this, Constant.CURRENT_LAT, location.getLatitude() + ""); | |
Utils.saveString(MainActivity.this, Constant.CURRENT_LONG, location.getLongitude() + ""); | |
} | |
@Override | |
public void onStatusChanged(String provider, int status, Bundle extras) { | |
} | |
@Override | |
public void onProviderEnabled(String provider) { | |
} | |
@Override | |
public void onProviderDisabled(String provider) { | |
} | |
} |
If done, then running your project. Hope there is no error :D
EmoticonEmoticon