Sunday, March 6, 2016

Pemanfaatan Google Maps dan Google Directions sebagai penunjuk jalan

Pemanfaatan Google Maps dan Google Directions sebagai penunjuk jalan sebenarnya mau saya buat seperti ini “Pemanfaatan Google Maps dan Google Directions sebagai penunjuk jalan menuju lokasi wisata yang ada di Jogja” kelihatan panjang banget dan mirip dengan judul skripsi 😀
Aplikasi android google maps directions
Tampilan Home Screen Aplikasi
Oke kali ini saya mau cerita mengenai sebuah aplikasi yang saya buat dalam waktu tidak terlalu lama, kenapa saya buat aplikasi ini, tujuannya adalah untuk membantu saya menemukan lokasi wisata yang ingin saya tuju, kemarin waktu libur imlek saya berencana untuk keluar dari rutinitas sehari-hari(ngoding, tidur, main dota) dengan mengunjungi lokasi wisata yang ada disekitaran jogja terutama di gunung kidul, bosen kalo mesti ke parangtritis lagi, 😀 jadilah ditetapkan,, “Yuk pantai, gunung kidul”.
Destinasinya sudah ditetapkan, kami akan ke salah satu pantai yang ada digunung kidul yaitu pantai Sadranan. Masalah lain muncul, tanya ke temen yang mau diajakin tahu jalannya atau tidak, dengan polos dan lugunya bilang, “gak ngerti… T.T (muka mewek)”, dan dijawab lagi dengan polos “owh (muka datar).
Jiwa IT nya lalu keluar, kenapa gak make google maps, owh iya, setelah dicek via google maps browser ternyata lumayan jauh, dan banyak persimpangan yang dapat membuat hati gegana (gelisah galau merana) karena nyasar T.T terus adalagi, gimana ntar kalo disana gak ada signal ? bisa po buka google maps 😀 owh owh
Jadi teringat beberapa tahun lalu ketika masih kuliah pernah buat sebuah aplikasi yang memanfaatkan google directions dan google maps untuk memandu ke lokasi wisata, setelah dicari – cari beberapa menit, gak ketemu sourcenya, ini akibat ganti komputer beberapa tahun lalu, dan sepertinya sourcenya gak ke copy, dulu masih polos gak ngerti cara make git T.T
gambaran aplikasi
Aplikasi android google maps directions
Tampilan ketika user memilih destination
Android apps google maps directions
Tampilan map dan rute ke lokasi tujuan
Android Apps Google Maps directions
Tetap dapat menggunakan maps walaupun kondisi tidak ada jaringan
Konsep aplikasinya adalah pengembangan dari artikel yang saya tulis duluuu sekali, bedanya adalah dah gak make AsyncTask, udah diganti networking library Volley, terus parsing JSONnnya gak make cara lama parsing satu persatu (lamaaa bro) udah make Gson kemudian database tidak menggunakan SQLite tapi menggunakan Realm salah satu database NoSQL yang ada di android.
Oke sekarang nyeritain alur aplikasinya seperti apa, jadi gini nanti apps akan coba mengambil data directions yang dihasilkan dari google directions, kemudian hasil JSONnya ini diparsing oleh library Gson dan polylinenya disimpan kedalam database Realm, setelah disimpan dalam database baru ditampilkan kedalam maps, kenapa disimpan kedalam database polylinenya ? agar nanti ketika dibuka untuk selanjutnya tidak memerlukan internet lagi, tinggal baca dari database hal ini untuk menanggulangi ketika diperjalanan tidak adanya koneksi internet tapi signal gps masih ada.
Sebelum user dapat menekan tombol generate route, user harus memasukkan starting point dimana rute akan mulai digenerate, saya menggunakan maps dan sebuah marker untuk meminta inputan user dimana starting pointya, classnya seperti ini
public class AddMapActivity extends FragmentActivity implements GoogleMap.OnMapClickListener, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private double lat, lng;
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
private Location location;
private GoogleApiClient googleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_map);
ButterKnife.inject(this);
setUpMapIfNeeded();
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this) // connection callback
.addOnConnectionFailedListener(this) // when connection failed
.addApi(LocationServices.API) // called api
.build();
}
@Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
@Override
protected void onStart() {
super.onStart();
googleApiClient.connect();
}
@Override
protected void onStop() {
super.onStop();
if (googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
}
/**
* Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly
* installed) and the map has not already been instantiated.. This will ensure that we only ever
* call {@link #setUpMap()} once when {@link #mMap} is not null.
* <p/>
* If it isn't installed {@link SupportMapFragment} (and
* {@link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to
* install/update the Google Play services APK on their device.
* <p/>
* A user can return to this FragmentActivity after following the prompt and correctly
* installing/updating/enabling the Google Play services. Since the FragmentActivity may not
* have been completely destroyed during this process (it is likely that it would only be
* stopped or paused), {@link #onCreate(Bundle)} may not be called again so we should call this
* method in {@link #onResume()} to guarantee that it will be called.
*/
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
}
}
/**
* This is where we can add markers or lines, add listeners or move the camera. In this case, we
* just add a marker near Africa.
* <p/>
* This should only be called once and when we are sure that {@link #mMap} is not null.
*/
private void setUpMap() {
mMap.setOnMapClickListener(this);
mMap.setMyLocationEnabled(true);
}
@Override
public void onMapClick(LatLng latLng) {
mMap.clear();
mMap.addMarker(new MarkerOptions()
.position(new LatLng(latLng.latitude, latLng.longitude))
.title("Starting Point")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker))
);
lat = latLng.latitude;
lng = latLng.longitude;
}
@OnClick(R.id.fab)
public void onFabClick() {
Toast.makeText(this, "fab click", Toast.LENGTH_SHORT).show();
Bundle data = new Bundle();
data.putDouble("lat", lat);
data.putDouble("lng", lng);
Intent resultIntent = new Intent();
resultIntent.putExtras(data);
setResult(RESULT_OK, resultIntent);
finish();
}
@Override
public void onConnected(Bundle bundle) {
if (location == null) {
// get last location device
location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (mMap != null) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 13));
mMap.addMarker(new MarkerOptions()
.position(new LatLng(location.getLatitude(), location.getLongitude()))
.title("Starting Point")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker))
);
lat = location.getLatitude();
lng = location.getLongitude();
Toast.makeText(this, "Lokasi kamu saat ini, sebagai patokan titik awal perjalanan kamu kak :')", Toast.LENGTH_LONG).show();
}
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
view rawAddMapActivity.java hosted with ❤ by GitHub
jika diperhatikan script diatas, saya menggunakan FusedLocationProvider untuk menentukan lokasi user saat ini berada, dapat dilihat dari kode dibawah
@Override
public void onConnected(Bundle bundle) {
if (location == null) {
// get last location device
location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (mMap != null) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 13));
mMap.addMarker(new MarkerOptions()
.position(new LatLng(location.getLatitude(), location.getLongitude()))
.title("Starting Point")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker))
);
lat = location.getLatitude();
lng = location.getLongitude();
Toast.makeText(this, "Lokasi kamu saat ini, sebagai patokan titik awal perjalanan kamu kak :')", Toast.LENGTH_LONG).show();
}
}
}
view rawgistfile1.java hosted with ❤ by GitHub
ketika googleApiClient berhasil terkoneksi, dan FusedLocationProvider dapat mengakses last location maka saya akan menggerakkan camera maps ke location user sekarang, kemudian menambahkan marker diatasnya.
Agar lebih fleksibel saya membuat user dapat memilih starting point sesuai dengan kehendaknya, caranya adalah dengan mengklik dimana saja diatas peta maka lokasi klik tersebut akan menjadi starting point, caranya dalah dengan menambahkan event onMapClickListener ke peta, setelah itu implement method onMapClick
@Override
public void onMapClick(LatLng latLng) {
mMap.clear();
mMap.addMarker(new MarkerOptions()
.position(new LatLng(latLng.latitude, latLng.longitude))
.title("Starting Point")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker))
);
lat = latLng.latitude;
lng = latLng.longitude;
}
view rawonMapClick hosted with ❤ by GitHub
setelah dirasa cukup user tinggal menekan tombol centang yang ada dibawah yang akan menjalankan code berikut
@OnClick(R.id.fab)
public void onFabClick() {
Toast.makeText(this, "fab click", Toast.LENGTH_SHORT).show();
Bundle data = new Bundle();
data.putDouble("lat", lat);
data.putDouble("lng", lng);
Intent resultIntent = new Intent();
resultIntent.putExtras(data);
setResult(RESULT_OK, resultIntent);
finish();
}
view rawgistfile1.java hosted with ❤ by GitHub
kode diatas adalah untuk mengembalikan ke activity sebelumnya dengan Result OK dan nilai latitude dan longitude yang sudah dipilih.
Selanjutnya user akan memilih destinasi wisata tujuan yang ditampilkan kedalam Spinner, lokasi didapet dari mana ? masih dihardcode, jadi langsung ditulis kedalam code, belom ada niat ambil dari sebuah API
/**
* hekz!
* Hardcode doloe gan..
* forgive me ~
*/
private void generateLocationDummy() {
locations.add(new Location("Sadranan", -8.146982, 110.6076521));
locations.add(new Location("Ngrenehan", -8.1235303, 110.5161231));
locations.add(new Location("Indrayanti", -8.1501091, 110.6121113));
locations.add(new Location("KaliBiru", -7.8017879,110.1318019));
}
view rawadd loc hosted with ❤ by GitHub
Setelah memilih destinasi maka selanjutnya tombol generate route akan memanggil activity ViewRoute dengan membawa beberapa parameter
@OnClick(R.id.btnGetRoute)
public void getRoute() {
if (!TextUtils.isEmpty(etFrom.getText())) {
Location loc = locations.get(spDestination.getSelectedItemPosition());
Bundle data = new Bundle();
data.putDouble("latAwal", lat);
data.putDouble("lngAwal", lng);
data.putDouble("latTujuan", loc.getLat());
data.putDouble("lngTujuan", loc.getLng());
data.putInt("status", MainActivity.FROM_NET);
data.putString("tujuan", loc.getName());
startActivity(new Intent(this, ViewRouteActivity.class).putExtras(data));
} else {
Toast.makeText(this, "can't empty", Toast.LENGTH_SHORT).show();
}
}
view rawgistfile1.java hosted with ❤ by GitHub
Setetal memilih starting point dan destinasi tujuan, langkah selanjutnya adalah mendapatkan titik-titik lokasi yang digunakan untuk menggambar jalur kedalam peta, dibagian inilah fungsi dari Google Directions, untuk melakukan request ke google directions saya menggunakan volleylibrary dengan class batuan JsonObjectRequestnya, sehingga hasil dari requestnya otomatis dibuatkan JsonObject
private void getDirections(String URL) {
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET,
URL, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
progressDialog.dismiss();
response = new Gson().fromJson(jsonObject.toString(), com.pratamawijaya.panggilpeta.json.Response.class);
Log.d("debug", "" + response.getRouteList().get(0).getLegsList().get(0).getDistance());
// Fetch Directions From Json
fetchDirection(response.getRouteList().get(0).getLegsList().get(0).getStepsList());
saveToDb(response.getRouteList().get(0).getLegsList().get(0));
// TODO: Save to DB
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
progressDialog.dismiss();
Log.d("error", "" + volleyError.toString());
}
});
progressDialog.show();
BaseApplication.getInstance().addToRequestQueue(request, "tag");
}
view rawgistfile1.java hosted with ❤ by GitHub
jika diperhatikan dari method getDirections didalam method onResponse saya akan memanggil method fetchDirections, dimana didalam method inilah proses pengambilan data berubah lat lng yang akan dijadikan polyline
private void fetchDirection(List<Steps> stepsList) {
Log.d("debug", "size list awal: " + latLngList.size());
for (Steps data : stepsList) {
// add start
latLngList.add(new LatLng(data.getStartLocation().getLat(), data.getStartLocation().getLng()));
// decode poly
List<LatLng> decodedPoly = Utils.decodePoly(data.getPolyline().getPoints());
for (LatLng point : decodedPoly)
latLngList.add(new LatLng(point.latitude, point.longitude));
latLngList.add(new LatLng(data.getEndLocation().getLat(), data.getEndLocation().getLng()));
// add end
}
Log.d("debug", "size list akhir : " + latLngList.size());
drawDirectionToMap(latLngList);
}
view rawfetchDirection hosted with ❤ by GitHub
setelah didapatkan polylinenya baru digambar kedalam mapsnya, prosesnya menggunakan method drawDirections berikut ini
private void drawDirectionToMap(List<LatLng> latLngList) {
PolylineOptions line = new PolylineOptions().width(3).color(Color.BLUE);
for (int i = 0; i < latLngList.size(); i++) {
line.add(latLngList.get(i));
}
mMap.addPolyline(line);
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latLngList.get(0).latitude, latLngList.get(0).longitude), 14));
// add marker diawal
mMap.addMarker(new MarkerOptions()
.position(new LatLng(latLngList.get(0).latitude, latLngList.get(0).longitude))
.title("starting point")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker))
);
// add marker di akhir
int index = latLngList.size() - 1;
mMap.addMarker(new MarkerOptions()
.position(new LatLng(latLngList.get(index).latitude, latLngList.get(index).longitude))
.title("end point")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker))
);
Toast.makeText(this, "Jalur berhasil digambar kak, hati2 dijalan pelan2 saja,,, ", Toast.LENGTH_SHORT).show();
}
view rawgistfile1.java hosted with ❤ by GitHub
nah untuk proses pengambilan data via internet seperti itu, lalu untuk yang offline alurnya seperti apa, nah alurnya seperti ini, semuanya berawal dari class MainActivity berikut ini
public class MainActivity extends BaseActivity implements RecyclerItemClickListener.OnItemClickListener {
public static final int FROM_LOCAL = 0;
public static final int FROM_NET = 1;
@InjectView(R.id.recyclerview)
RecyclerView recyclerView;
@InjectView(R.id.emptytext)
TextView emptyText;
@InjectView(R.id.fab)
FloatingActionButton fab;
private ListRouteAdapter adapterRoute;
private List<LocationModel> locationModels;
private Realm realm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
realm = Realm.getInstance(this);
getSupportActionBar().setTitle(getResources().getString(R.string.txt_liburan));
locationModels = new ArrayList<>();
adapterRoute = new ListRouteAdapter(this, locationModels);
updateView();
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapterRoute);
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, this));
readDataFromDb();
}
private void updateView() {
if (locationModels.isEmpty()) {
emptyText.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
emptyText.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
}
private void readDataFromDb() {
if (locationModels.size() > 0)
locationModels.clear();
RealmResults<LocationModel> result = realm
.where(LocationModel.class)
.findAll();
// sortiny by id.
// show greater first
result.sort("id", RealmResults.SORT_ORDER_DESCENDING);
for (LocationModel data : result) {
Log.d("tag", "datanya " + data.getId());
locationModels.add(data);
}
// notify adapter
adapterRoute.notifyDataSetChanged();
// update view
updateView();
}
@OnClick(R.id.fab)
public void onFabClick() {
startActivity(new Intent(this, AddRouteActivity.class));
}
@Override
public void onItemClick(View v, int position) {
Toast.makeText(this, "" + locationModels.get(position).getTujuan(), Toast.LENGTH_SHORT).show();
Bundle data = new Bundle();
data.putInt("status", FROM_LOCAL);
data.putString("id", locationModels.get(position).getId());
startActivity(new Intent(this, ViewRouteActivity.class).putExtras(data));
}
@Override
protected void onResume() {
super.onResume();
readDataFromDb();
}
}
view rawMainActivity hosted with ❤ by GitHub
Yang pertama adalah jelas membaca data yang ada ditabase Realm, method yang bertanggung jawab untuk tugas itu adalah method readDataFromDb berikut ini
private void readDataFromDb() {
if (locationModels.size() > 0)
locationModels.clear();
RealmResults<LocationModel> result = realm
.where(LocationModel.class)
.findAll();
// sortiny by id.
// show greater first
result.sort("id", RealmResults.SORT_ORDER_DESCENDING);
for (LocationModel data : result) {
Log.d("tag", "datanya " + data.getId());
locationModels.add(data);
}
// notify adapter
adapterRoute.notifyDataSetChanged();
// update view
updateView();
}
view rawgistfile1.java hosted with ❤ by GitHub
intinya dari method itu adalah mencoba untuk query kedalam class model, kemudian disorting berdasarkan id secara descending, saya set seperti ini saya pengennya rute yang terakhir saya generate yang akan berada diatas sendiri.
kemudian untuk event agar ketika list route di klik saya menggunakan event RecyclerItemClickListener.OnItemClickListener yang dibuat sendiri dan berada di package helper, isi dari methodnya adalah
@Override
public void onItemClick(View v, int position) {
Toast.makeText(this, "" + locationModels.get(position).getTujuan(), Toast.LENGTH_SHORT).show();
Bundle data = new Bundle();
data.putInt("status", FROM_LOCAL);
data.putString("id", locationModels.get(position).getId());
startActivity(new Intent(this, ViewRouteActivity.class).putExtras(data));
}
view rawgistfile1.java hosted with ❤ by GitHub
yang perlu diperhatikan disini adalah saya menambahkan key untuk menentukan route yang digambar itu dari database atau dari internet, dan id dari database rute yang akan saya gambar.
Selanjutnya kembali lagi ke class ViewRouteActivity untuk melihat bagaiman proses menggambar polyline yang didapat dari database. Proses utamanya ada di method onCreate yang ada diclass ViewRoute activity berikut
data = getIntent().getExtras();
if (data.getInt("status") == MainActivity.FROM_LOCAL) {
// baca db
latLngList = readDataFromDB(data.getString("id"));
// draw
drawDirectionToMap(latLngList);
} else {
latAwal = data.getDouble("latAwal");
lngAwal = data.getDouble("lngAwal");
latTujuan = data.getDouble("latTujuan");
lngTujuan = data.getDouble("lngTujuan");
tujuan = data.getString("tujuan");
getDirections(getGoogleDirectionsUrl(latAwal, lngAwal, latTujuan, lngTujuan));
}
view rawgistfile1.java hosted with ❤ by GitHub
pertama saya akan cek statusnya apakah rute tersebut diambil dari database atau dari internet, cara ngeceknya make key itu tadi, di bagian MainActivity saya membuat key untuk membedakan data diambil dari db maupun internet
jika data yang diambil dari database, maka selanjutnya adalah melalukan read ke database berdasarkan dari id rute,
sedangkan isi dari method readDataFromDB itu sendiri adalah seperti ini
private List<LatLng> readDataFromDB(String id) {
RealmResults<LocationModel> result = realm.where(LocationModel.class).equalTo("id", id).findAll();
List<LatLng> listlatlng = new ArrayList<>();
for (LatLngModel data : result.get(0).getLatLngRealmList())
listlatlng.add(new LatLng(data.getLat(), data.getLng()));
return listlatlng;
}
view rawgistfile1.java hosted with ❤ by GitHub
di method tersebut saya coba melakukan query ke LocationModel class dengan id berdasarkan dari id yang dibawa class sebelumnya, kemudian memasukkan data lat lng kedalam list yang disiapkan untuk menampung data latitude dan longitude, setelah data berhasil dibaca kemudian method drawDirectionToMap dijalankan dengan parameter List dari latlng yang telah didapatkan sebelumnya.
Sumber : https://pratamawijaya.com/programming/android-programming/android-studio-project-pemanfaatan-google-maps-dan-google-directions-sebagai-penunjuk-jalan

BERKOMENTARLAH YANG SANTUN, JANGAN SPAM, AYO BERKOMENTARLAH DISINI. . .

Ditulis Oleh : I Gusti Ngurah Made Ardika ~ Mari Berbagi dan Belajar Bersama

Artikel Pemanfaatan Google Maps dan Google Directions sebagai penunjuk jalan ini diposting oleh I Gusti Ngurah Made Ardika pada hari Sunday, March 6, 2016. Terimakasih atas kunjungan Anda serta kesediaan Anda membaca artikel ini. Kritik dan saran dapat anda sampaikan melalui kotak komentar.

0 komentar:

Post a Comment

Mari kita saling berkomentar. Jika kalian suka dengan artikel ini, ayo kita "Share" untuk membagikan informasi ini kepada sobat yang lain agar lebih bermanfaat. Terima kasih, Salam Blogger . . .