Menampilkan Peta Dengan Google Maps API


Pada artikel Memakai Database SQLite Di Android, saya membuat aplikasi yang mencari dan menyimpan koordinat lokasi yang diperoleh melalui GPS. Walaupun, saya bisa menampilkan lokasi ini satu per satu melalui Intent, akan lebih baik bila saya menambahkan fitur untuk menampilkan seluruh lokasi yang tersimpan di database ke dalam sebuah peta tunggal. Dengan demikian, saya bisa menganalisa hubungan setiap lokasi secara mudah. Untuk itu, saya perlu menyisipkan peta langsung di dalam aplikasi sehingga bisa saya atur sesuka hati.

Akan tetapi membuat kode program untuk menampilkan peta bukanlah hal mudah dan bisa membutuhkan waktu lama. Salah satu solusi yang lebih mudah adalah dengan memakai Google Maps yang bisa disisipkan ke dalam aplikasi Android melalui Google Maps API yang merupakan bagian dari layanan dari Google Play Services. Fasilitas ini bukan bagian dari Android Open Source Project (AOSP) melainkan layanan tersendiri dari Google. Hal ini berarti perangkat Android yang murni memakai AOSP (produsennya tidak ‘membayar’ lebih kepada Google) tidak bisa menjalankan aplikasi yang memakai Google Play Services. Selain itu, walaupun Google Maps API bisa dipakai secara gratis oleh programmer Android, penggunaan yang berlebihan seperti membuka lebih dari 25.000 peta setiap hari selama lebih dari 90 hari berturut-turut akan dikenakan biaya.

Untuk memakai Google Play Services, saya perlu menambahkan baris berikut ini pada build.gradle (modul):

...
dependencies {
    ...
    compile 'com.android.support:appcompat-v7:22.0.0'
    compile 'com.google.android.gms:play-services:7.0.0'
}

Saya kemudian men-klik Sync Now agar Android Studio men-download dependency (file JAR) yang dibutuhkan. Setelah itu, saya juga menambahkan baris berikut ini pada AndroidManifest.xml:

<manifest ...>

  ...

  <application ...>

    ...

    <meta-data android:name="com.google.android.gms.version"
       android:value="@integer/google_play_services_version" />

  </application>

</manifest>

Setiap aplikasi Android selalu di-sign oleh sebuah sertifikat digital. Khusus untuk aplikasi yang dijalankan pada perangkat atau emulator sebagai debug release, saya dapat menemukan lokasi sertifikat digital tersebut di ~/.android/debug.keystore. Sebagai contoh, di Linux, saya dapat memberikan perintah berikut ini:

$  keytool -list -v -keystore ~/.android/debug.keystore 
-alias androiddebugkey -storepass android -keypass android

untuk menampilkan informasi sertifikat digital yang dipakai oleh Android Studio saat menghasilkan aplikasi pada debug release. Dengan kata lain, semua aplikasi yang saya jalankan pada debug release bisa dikenali melalui sertifikat digital ini.

Saya kemudian mencatat nilai SHA1 pada output di atas. Nilai ini dibutuhkan untuk mendapatkan sebuah Android API key yang dapat dipakai di aplikasi saya. Untuk memperoleh key ini, saya membuka https://console.developers.google.com. Pada situs tersebut, saya men-klik tombol Create Project. Setelah proyek dibuat, saya memilih APIs & auth, APIs, Google Maps APIs, dan men-klik pada Google Maps Android API. Saya kemudian men-klik tombol Enable API. Setelah itu, saya memilih APIs & auth, Credentials dan men-klik pada Create new Key. Pada dialog yang muncul, saya memilih Android key. Saya perlu mengisi input yang ada dengan nilai SHA1 yang saya peroleh dari sertifikat digital diikuti dengan tanda titik koma beserta nama package seperti XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX;com.snake.latihanku. Setelah selesai, saya akan memperoleh sebuah API key yang bisa dipakai pada proyek Android saya.

Untuk memakai API key yang dihasilkan dari Google, saya menambahkan baris berikut ini pada AndroidManifest.xml:

<manifest ...>

  ...

  <application ...>

    ...

    <meta-data android:name="com.google.android.geo.API_KEY"
       android:value="xxxxxxxxxxxxxxxxx" />

  </application>

</manifest>

Berkat key unik ini, Google dapat mengenali seberapa sering aplikasi saya memanggil Google Maps API. Pengunaan berlebihan yang membutuhkan pembayaran dihitung berdasarkan seberapa sering API dipanggil melalui key ini.

Untuk memakai Google Maps API, saya perlu terhubung ke server Google Maps melalui internet. Selain itu, ia juga akan men-cache data ke penyimpanan eksternal guna mengirit akses internet. Oleh sebab itu, saya menambahkan permission berikut ini di AndroidManifest.xml:

<manifest ...>

  ...

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  ...

</manifest>

Sekarang, saya siap untuk membuat kode program. Saya akan mulai dengan membuat sebuah menu baru seperti:

<menu ...>

  ...

  <item android:id="@+id/menu_semua" app:showAsAction="ifRoom"
     android:title="Lihat Semua" />

  ...

</menu>

Pada saat menu ini di-klik, kode program berikut ini akan dikerjakan:

public class LokasiActivity extends Activity implements LocationListener, SensorEventListener {

  ...

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    ...
    // Tampilkan semua
    menu.findItem(R.id.menu_semua).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
      @Override
      public boolean onMenuItemClick(MenuItem item) {
        startActivity(new Intent(LokasiActivity.this, SemuaLokasiActivity.class));
        return true;
      }
    });

    return true;
  }

  ...

}

Kode program di atas akan menjalankan SemuaLokasiActivity yang isinya seperti berikut ini:

public class SemuaLokasiActivity extends Activity implements OnMapReadyCallback {

    private MapFragment mapFragment;
    private LinearLayout layout;
    private List<Lokasi> daftarLokasi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        layout = new LinearLayout(this);
        layout.setId(View.generateViewId());
        setContentView(layout);
        GoogleMapOptions options = new GoogleMapOptions();
        options.mapType(GoogleMap.MAP_TYPE_SATELLITE);
        mapFragment = MapFragment.newInstance(options);
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.add(layout.getId(), mapFragment);
        fragmentTransaction.commit();

        // Baca semua lokasi dari database SQLite
        daftarLokasi = new ArrayList<>();
        new Thread(new Runnable() {
            @Override
            public void run() {
                DbHelper dbHelper = new DbHelper(SemuaLokasiActivity.this);
                SQLiteDatabase db = dbHelper.getReadableDatabase();
                Cursor cursor = db.rawQuery("SELECT * FROM lokasi", null);
                while (cursor.moveToNext()) {
                    Lokasi lokasi = new Lokasi(
                        cursor.getString(cursor.getColumnIndexOrThrow("nama")),
                        cursor.getDouble(cursor.getColumnIndexOrThrow("longitude")),
                        cursor.getDouble(cursor.getColumnIndexOrThrow("latitude")),
                        cursor.getDouble(cursor.getColumnIndexOrThrow("altitude")),
                        cursor.getFloat(cursor.getColumnIndexOrThrow("akurasi")),
                        cursor.getFloat(cursor.getColumnIndexOrThrow("azimuth"))
                    );
                    daftarLokasi.add(lokasi);

                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mapFragment.getMapAsync(SemuaLokasiActivity.this);
                    }
                });
            }
        }).start();
    }


    @Override
    public void onMapReady(GoogleMap map) {
        for (Lokasi lokasi: daftarLokasi) {
            map.addMarker(new MarkerOptions()
                .position(new LatLng(lokasi.getLatitude(), lokasi.getLongitude()))
                .title(lokasi.getNama())
                .flat(true)
                .rotation(lokasi.getAzimuth())
        );
        }
    }
}

Pada method onCreate() di atas, saya mendaftarkan sebuah MapFragment baru sebagai tampilan untuk activity ini. Kode program options.mapType(GoogleMap.MAP_TYPE_SATELLITE) menyebabkan peta yang ditampilkan adalah hasil pencitraan dari satelit. Setelah itu, saya membuat thread baru untuk membaca data lokasi dari database. Di dalam thread baru tersebut, setelah berhasil membaca dari database, saya memanggil mapFragment.getMapAsync() untuk menambahkan titik marker pada peta. Karena getMapAsync() harus dikerjakan di UI thread (main thread), maka saya memanggilnya melalui runOnUiThread().

Setelah peta berhasil ditampilkan, kode program onMapReady() akan dikerjakan. Pada kode program di method onMapReady(), saya menambahkan marker pada peta untuk masing-masing lokasi yang tersimpan di database. Saya juga menggunakan method rotation() untuk memutar marker sesuai dengan arah kompas yang terekam.

Sampai disini, bila aplikasi dijalankan dan saya memilih menu Lihat Semua, maka sebuah peta (yang berdasarkan Google Maps) akan ditampilkan dimana terdapat marker untuk setiap posisi yang pernah tersimpan, seperti yang terlihat pada gambar berikut ini:

Contoh tampilan aplikasi yang mengandung Google Maps beserta marker buatan sendiri

Contoh tampilan aplikasi yang mengandung Google Maps beserta marker buatan sendiri

Agar lebih jelas, saya bisa menampilkan garis yang menghubungkan masing-masing posisi tersebut. Untuk itu, saya mengubah kode program untuk method onMapReady() menjadi seperti berikut ini:

...
@Override
public void onMapReady(GoogleMap map) {
  PolylineOptions lineOptions = new PolylineOptions();
  for (Lokasi lokasi: daftarLokasi) {
    LatLng posisi = new LatLng(lokasi.getLatitude(), lokasi.getLongitude());
    map.addMarker(new MarkerOptions()
      .position(posisi)
      .title(lokasi.getNama())
      .flat(true)
      .rotation(lokasi.getAzimuth())
    );
    lineOptions.add(posisi);
  }
  map.addPolyline(lineOptions.color(Color.BLUE));
}
...

Pada kode program di atas, saya memanggil method addPolyline() dari GoogleMap untuk menggambar garis pada peta. Bila saya menjalankan aplikasi, kali ini setiap titik yang tersimpan di database akan ditampilkan dengan dihubungkan oleh sebuah garis berwarna biru, seperti yang terlihat pada gambar berikut ini:

Menggambar garis di Google Maps

Menggambar garis di Google Maps

Sebagai pelengkap, saya akan menampilkan informasi jarak sebuah lokasi terhadap lokasi sebelumnya, dengan mengubah method onMapReady() menjadi seperti berikut ini:

...
@Override
public void onMapReady(GoogleMap map) {
  PolylineOptions lineOptions = new PolylineOptions();
  Lokasi lokasiSebelumnya = null;
  float[] jarak = new float[1];
  for (Lokasi lokasi: daftarLokasi) {
    LatLng posisi = new LatLng(lokasi.getLatitude(), lokasi.getLongitude());
    MarkerOptions markerOptions = new MarkerOptions()
      .position(posisi)
      .title(lokasi.getNama())
      .flat(true)
      .rotation(lokasi.getAzimuth());
    if (lokasiSebelumnya != null) {
      Location.distanceBetween(lokasiSebelumnya.getLatitude(), lokasiSebelumnya.getLongitude(),
        posisi.latitude, posisi.longitude, jarak);
      markerOptions.snippet("Jarak Ke " + lokasiSebelumnya.getNama() + " = " + jarak[0] + " m");
    }
    map.addMarker(markerOptions);
    lineOptions.add(posisi);
    lokasiSebelumnya = lokasi;
  }
  map.addPolyline(lineOptions.color(Color.BLUE));
}
...

Pada kode program di atas, saya menghitung jarak dari lokasi dengan menggunakan method Location.distanceBetween(). Method ini akan menyimpan nilai jarak dalam satuan meter pada elemen pertama dari array yang dilewatkan sebagai argumen. Untuk menampilkan informasi jarak ini pada saat pengguna menyentuh sebuah marker, saya menggunakan method snippet() pada MarkerOptions untuk marker tersebut. Bila saya menyentuh sebuah marker, saya akan memperoleh informasi jarak seperti yang terlihat pada gambar berikut ini:

Menambahkan snippet berisi informasi jarak ke marker di Google Maps

Menambahkan snippet berisi informasi jarak ke marker di Google Maps

Perihal Solid Snake
I'm nothing...

One Response to Menampilkan Peta Dengan Google Maps API

  1. Rifqi Zuliansyah mengatakan:

    Halo mas🙂
    Terimakasih banyak mas atas postingnya tentang tutorial bagaimana cara membuat aplikasi android tentang map. Kebetulan saya sedang belajar juga tentang map baru2 ini, dan postingan ini sangat bermanfaat.
    Saya sudah mencoba tutorial mas dari mencari lokasi di gps, database, dan menampilkan peta mas. Ini sangat membantu saya belajar yang sedikit kesulitan memahami kalau tutorial bahasa inggris. Hehehe
    Tapi ketika saya mencoba masih sering terjadi error karena beberapa bagian sourcecodenya hilang. Saya ingin belajar lebih detail mas, kalau berkenan apakah saya boleh minta sourcecode program ini yang versi full mas? Supaya saya lebih mudah memahaminya bagian-per-bagian.
    Saya sangat berterimakasih apabila mas nya berkenan. Hehe

    Sebelumnya Terimakasih banyak atas postinya ya mas, sangat membantu sekali.

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: