Tutorial Reverse Geocoding : Mengubah Koordinat Menjadi Alamat di Android

Halo semua, melanjutkan tutorial sebelumnya tentang mendapatkan lokasi pengguna di Android. Kali ini kita masih bermain-main dengan LocationServices API, tentang bagaimana mengubah koordinat (latitude, longitude) menjadi nama alamat menggunakan teknik reverse geocoding dengan Android Geocoder. 🙂

Belajar reverse geocoding konversi lat long menjadi alamat

Dengan menggunakan Fused Location API, kita bisa mendapatkan lokasi pengguna di Android. Naamun setelah mendapatkan lokasi pengguna kita hanya mendapatkan latitude dan longitude yang susah untuk dipahami/dimengerti, kecuali jika kita tampilkan lat long tersebut di atas peta. Karena itu supaya lebih mudah dibaca, kita bisa mengkonversi koordinat tersebut menggunakan teknik reverse geocoding. Dengan bantuan dari built-in API Android Geocoder. 🙂

Pre-Requisites

Seperti biasa kita akan membuat project Hello World dulu di Android Studio. Karena project ini merupakan lanjutan dari tutorial Fused Location API yang sebelumnya saya buat. Maka ada baiknya jika kalian langsung download saja source code nya dari GitHub saya.

Jika sudah, maka pada layout activity_main.xml, kalian bisa tambahkan satu buah Button untuk trigger proses reverse geocoding-nya. Langkah selanjutnya adalah…

Membuat Geocoder Intent Services

Oke, karena proses reverse geocoding ini merupakan sebuah proses yang bisa berjalan lama, dan kemungkinan hasilnya juga bisa bermacam-macam maka reverse geocoding akan dijalankan di background proses menggunakan IntentService. Buatlah sebuah class bernama GeocoderIntentService.

Oh iya, sebelumnya kalian bisa membuat class pembantu bernama Constants.java. Karena kita akan banyak menggunakan constant String di sini.

Constants.java

package id.web.twoh.placesapitutorial.util;

/**
 * Created by Hafizh Herdi on 2/12/2017.
 */

public final class Constants {
    public static final int SUCCESS_RESULT = 0;
    public static final int FAILURE_RESULT = 1;
    public static final String PACKAGE_NAME =
            "id.web.twoh.placesapitutorial";
    public static final String RECEIVER = PACKAGE_NAME + ".RECEIVER";
    public static final String RESULT_DATA_KEY = PACKAGE_NAME +
            ".RESULT_DATA_KEY";
    public static final String LOCATION_DATA_EXTRA = PACKAGE_NAME +
            ".LOCATION_DATA_EXTRA";
}

GeocoderIntentService.java

import android.app.IntentService;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.text.TextUtils;
import android.util.Log;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import id.web.twoh.placesapitutorial.util.Constants;

/**
 * Created by Hafizh Herdi on 2/12/2017.
 */

public class GeocoderIntentService extends IntentService {

    private static final String TAG = GeocoderIntentService.class.getSimpleName();

    protected ResultReceiver mReceiver;

    public GeocoderIntentService() {
        // Use the TAG to name the worker thread.
        super(TAG);
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        String errorMessage = "";

        mReceiver = intent.getParcelableExtra(Constants.RECEIVER);

        // Cek apakah ada receiver untuk menerima hasil
        if (mReceiver == null) {
            Log.wtf(TAG, "Tidak ada receiver, sehingga hasil tidak bisa dikirim");
            return;
        }

        // Mendapatkan location yang dikirim ke intent service lewat extra
        Location location = intent.getParcelableExtra(Constants.LOCATION_DATA_EXTRA);

        // Make sure jika location yang dikirim tidak null
        if (location == null) {
            errorMessage = "Location tidak ditemukan";
            Log.wtf(TAG, errorMessage);
            deliverResultToReceiver(Constants.FAILURE_RESULT, errorMessage);
            return;
        }

        Geocoder geocoder = new Geocoder(this, Locale.getDefault());

        List<Address> addresses = null;

        try {

            /**
             * Proses reverse geocoding
             */
            addresses = geocoder.getFromLocation(
                    location.getLatitude(),
                    location.getLongitude(),
                    1);
        } catch (IOException ioException) {
            // Menangkap apabila ada I/O atau jaringan error
            errorMessage = "Location Service is not available";
            ioException.printStackTrace();
            Log.e(TAG, errorMessage, ioException);
        } catch (IllegalArgumentException illegalArgumentException) {
            // Apabila invalid latitude longitude
            errorMessage = "Invalid latitude longitude";
            Log.e(TAG, errorMessage + ". " +
                    "Latitude = " + location.getLatitude() +
                    ", Longitude = " + location.getLongitude(), illegalArgumentException);
        }

        // Apabila tidak ada alamat yang bisa ditemukan
        if (addresses == null || addresses.size()  == 0) {
            if (errorMessage.isEmpty()) {
                errorMessage = "Alamat tidak ditemukan";
                Log.e(TAG, errorMessage);
            }
            deliverResultToReceiver(Constants.FAILURE_RESULT, errorMessage);
        } else {
            Address address = addresses.get(0);
            ArrayList<String> addressFragments = new ArrayList<>();

            /**
             * Kalian juga bisa mendapatkan detail alamat lainnya
             * seperti kelurahan, kecamatan, kodepos dsb dalam istilah Inggrisnya
             * Contoh :
             * getLocality() ("Mountain View", for example)
             * getAdminArea() ("CA", for example)
             * getPostalCode() ("94043", for example)
             * getCountryCode() ("US", for example)
             * getCountryName() ("United States", for example)
             */

            for(int i = 0; i < address.getMaxAddressLineIndex(); i++) {
                addressFragments.add(address.getAddressLine(i));
            }
            Log.i(TAG, "alamat ditemukan");
            deliverResultToReceiver(Constants.SUCCESS_RESULT,
                    TextUtils.join(System.getProperty("line.separator"), addressFragments));
        }
    }

    /**
     * Sends a resultCode and message to the receiver.
     */
    private void deliverResultToReceiver(int resultCode, String message) {
        Bundle bundle = new Bundle();
        bundle.putString(Constants.RESULT_DATA_KEY, message);
        mReceiver.send(resultCode, bundle);
    }

}

Cara kerja IntentService di atas pada dasarnya adalah melakukan proses reverse geocoding (ubah koordinat menjadi alamat. Kemudian cek apakah ada alamat yang ditemukan, jika ada maka hasilnya akan dikembalikan lewat receiver.

Membuat Geocoder Result Receiver

Kita sudah membuat IntentService-nya, sekarang kita akan membuat ResultReceiver untuk menerima hasil balikan dari proses reverse geocoding tersebut, berupa alamat atau pesan error jika terjadi kendala. Caranya tambahkan class GeocoderResultReceiver pada MainActivity.java sebagai nested class.

GeocoderResultReceiver.java

    protected String address;

    class GeocoderResultReceiver extends ResultReceiver {
        public GeocoderResultReceiver(Handler handler) {
            super(handler);
        }

        /**
         *  Menerima balikan data dari GeocoderIntentService and menampilkan Toast di MainActivity.
         */
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {

            // Menampilkan alamat, atau error yang didapat dari proses reverse geocoding
            address = resultData.getString(Constants.RESULT_DATA_KEY);

            // Memunculkan toast message jika ada alamat ditemukan
            if (resultCode == Constants.SUCCESS_RESULT) {
                Toast.makeText(MainActivity.this, "Alamat ditemukan \n" +
                        address, Toast.LENGTH_LONG).show();
            }

            dialog.dismiss();
        }
    }

Jika ada alamat yang didapatkan, maka ResultReceiver akan memunculkan sebuah Toast.

Memanggil IntentService dari MainActivity.java

Langkah selanjutnya adalah memanggil IntentService dari MainActivity.java. Sebelum itu, mari kita menginitialize variable-variable yang dibutuhkan di MainActivity.java.

Initialize ResultReceiver

private GeocoderResultReceiver geocoderReceiver;
private Button btGeocoding;

// letakkan method pemanggilan ini di dalam onCreate
geocoderReceiver = new GeocoderResultReceiver(new Handler());
btGeocoding = (Button) findViewById(R.id.bt_geoCoding);

Setelah itu kita akan membuat method startIntentService() di MainActivity, untuk menyalakan GeocoderIntentService. Isi methodnya seperti di bawah :

    protected void startIntentService() {
        // Membuat intent yang mengarah ke IntentService untuk proses reverse geocoding
        Intent intent = new Intent(this, GeocoderIntentService.class);

        // Mengirim ResultReceiver sebagai extra ke intent service.
        intent.putExtra(Constants.RECEIVER, geocoderReceiver);

        // Mengirim location data sebagai extra juga ke intent service.
        intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);

        // Start the service. If the service isn't already running, it is instantiated and started
        // (creating a process for it if needed); if it is running then it remains running. The
        // service kills itself automatically once all intents are processed.
        // tl;dr = menyalakan intent service 🙂
        startService(intent);
    }

Kemudian kita set onClickListener pada tombol btGeocoding, supaya saat diklik nanti proses intentService nya akan dijalankan

        btGeocoding.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {          
                if(mGoogleApiClient.isConnected()){
                    startIntentService();
                }
            }
        });

Basically, that’s all.
Langkah terakhir adalah me-register IntentService tersebut pada AndroidManifest.xml

    <application>
        <activity>
        </activity>
        <service android:name=".GeocoderIntentService" android:exported="false"/>
    </application>

Jangan lupa juga untuk tambahkan permission

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Demo

Beginilah tampilan jika aplikasi dijalankan :

Android Reverse Geocoding sample

Android Reverse Geocoding sample

Kita akan klik tombol “Get Location” terlebih dahulu. Sekadar untuk memastikan apakah ada lat lng yang didapat. Jika sudah kita bisa lanjut klik tombol “Get Coordinate”, tunggu sejenak dan akan muncul alamat hasil reverse geocode dari koordinat tadi. 🙂

That’s all. Source code bisa didownload di Github. Jangan lupa untuk star project nya dan juga follow GitHub saya. 🙂 Silahkan tanya di bagian komentar apabila ada yang kurang jelas.



Download aplikasi kami di Google Play Store


Leave a Reply