Selasa, 24 Februari 2015

Membuat Aplikasi Location Based Services di Android Menggunakan Maps API v2

Kalau di lihat sampai sekarang masih banyak pengunjung yang mengakses dan bertanya-tanya tentang tutorial lama  berjudul membuat aplikasi location based services di Android. Tentu saja tutorial itu sudah tidak berlaku lagi, karena sekarang sudah jaman nya menggunakan Maps API v2, oleh karena itu di bawah ini akan di bahas bagaimana cara membuat aplikasi LBS menggunakan Maps API v2.


TWOH Maps v2

Tampilan Awal TWOH Maps v2 | (c) pepper artgerm.deviantart.com
Jika ada yang belum pernah dengar tentang LBS/Location Based Service, LBS atau bahasa Indonesianya Layanan Berbasis Lokasi adalah suatu sistem yang menyediakan layanan yang mempunyai lokasi geografis sehingga bisa kita lihat di peta. Dan salah satu sumber data geografis tersebut yang saat ini sangat mudah kita dapatkan adalah berupa koordinat lokasi yang diambil dari smartphone kita. Saat ini saya akan mendemonstrasikan bagaimana untuk mengambil lokasi dari smartphone Android kita.
Android mempunyai dua macam jenis lokasi sendiri, yaitu coarse-location dan fine-location. Lokasi coarse/kasar adalah lokasi user yang ditentukan lewat BTS terdekat, mempunyai presisi yang tidak akurat, namun hemat baterai. Sedangkan lokasi fine-location/lokasi halus, adalah lokasi user yang didapatkan melalui GPS yang sekarang sudah umum ada di perangkat Android. Fine-location mempunyai presisi yang lebih tinggi, namun boros baterai.

Pada Android, penentuan lokasi ini semua diatur oleh sebuah kelas yang bernama LocationManager, jadi location manager-lah yang akan menentukan kapan kita harus memakai fine-location, atau coarse-location apabila suatu saat GPS dimatikan. Location Manager juga secara otomatis akan mendeteksi perubahan lokasi yang terjadi, karena dia mempunyai semacam listener class yang bernama LocationListener. Kelas itulah yang akan memantau semua event, seperti perubahan lokasi, provider berubah, dan akan menyesuaikan pendeteksian lokasi sesuai dengan keadaan yang ada.

Pre-Requisites

Untuk membuat tutorial ini, kalian harus mempelajari beberapa tutorial yang pernah saya tulis sebelumnya. Karena itu saya sarankan agar kalian membaca daftar tutorial di bawah ini sebelum melanjutkan ke langkah berikutnya :
Pada link ketiga, kalian akan belajar bahwa sebenarnya kita bisa menampilkan lokasi pengguna pada peta hanya dengan mengklik tombol pada peta. Namun itu adalah fungsi yang sudah ada di Android Maps, dan kita tidak bisa mendapatkan data koordinat dari sana.

Down to Code

Oke, pertama-tama kita akan membuat tampilannya. Sama seperti di postingan sebelumnya, aplikasi ini akan mempunyai dua tampilan, yaitu tampilan Menu dan tampilan Maps yang akan menampilkan peta dan lokasi pengguna.
Oh ya, jika kalian menggunakan SDK Android terbaru, maka Main Activity yang ter-create akan mempunyai dua buah layout xml, yaitu layout untuk Activity tersebut dan layout untuk Fragment. Berikut ini adalah layout untuk Activity-nya :
activity_main.xml
?
1
2
3
4
5
6
7
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="id.web.twoh.twohmaps.MainActivity"
    tools:ignore="MergeRootFrame" />
Dan ini adalah layout untuk fragment, berisi tombol-tombol navigasi, yaitu tombol Check-In, tombol Get Location, tombol About, dan tombol View On Map :
fragment_main.xml
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    android:background="@drawable/bg_main"
    android:gravity="center_horizontal|center_vertical"
    tools:context="id.web.twoh.twohmaps.MainActivity$PlaceholderFragment" >
   <TextView
        android:id="@+id/NamaProgram"
        android:text="TWOH Maps v2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ffffff"
        android:textStyle="bold"
        />
    <Button
         android:id="@+id/btGetLocation"
         android:text="Get Location"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
    />
    <Button
         android:id="@+id/btViewOnMap"
         android:text="View On Map"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
    />
    <Button
         android:id="@+id/btCheckIn"
         android:text="Check In"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
    />
    <Button
         android:id="@+id/btAbout"
         android:text="About"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
    />
</LinearLayout>
Kemudian untuk isi dari MainActivity nya sendiri adalah sebagai berikut :
?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package id.web.twoh.twohmaps;
import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
import id.web.twoh.twohmaps.R;
public class MainActivity extends ActionBarActivity {
    protected LocationManager locationManager;
    private static final long MINIMUM_DISTANCE_CHANGE_FOR_UPDATES = 10; // dalam Meters
    private static final long MINIMUM_TIME_BETWEEN_UPDATES = 60000; // dalam Milliseconds
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment()).commit();
        }
         locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            locationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    MINIMUM_TIME_BETWEEN_UPDATES,
                    MINIMUM_DISTANCE_CHANGE_FOR_UPDATES,
                    new MyLocationListener()
            );
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    protected void showCurrentLocation() {
        Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (location != null) {
            String message = String.format(
                    "Lokasi saat ini \n Longitude: %1$s \n Latitude: %2$s",
                    location.getLongitude(), location.getLatitude()
            );
            Toast.makeText(this, message,
                    Toast.LENGTH_LONG).show();
            }
    }  
    private class MyLocationListener implements LocationListener {
        public void onLocationChanged(Location location) {
            String message = String.format(
                    "Deteksi Lokasi Baru \n Longitude: %1$s \n Latitude: %2$s",
                    location.getLongitude(), location.getLatitude()
            );
            Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
            //switchToMap();
        }
        public void onStatusChanged(String s, int i, Bundle b) {
            Toast.makeText(MainActivity.this, "Status provider berubah",
                    Toast.LENGTH_LONG).show();
        }
        public void onProviderDisabled(String s) {
            Toast.makeText(MainActivity.this,
                    "Provider dinonaktifkan oleh user, GPS off",
                    Toast.LENGTH_LONG).show();
        }
        public void onProviderEnabled(String s) {
            Toast.makeText(MainActivity.this,
                    "Provider diaktifkan oleh user, GPS on",
                    Toast.LENGTH_LONG).show();
        }
    }
    public static class PlaceholderFragment extends Fragment {
        private Button btMaps;
        private Button btCheckIn;
        private Button btGetLocation;
        Location location;
        public PlaceholderFragment() {
        }
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container,
                    false);
            btMaps = (Button)rootView.findViewById(R.id.btViewOnMap);
            btMaps.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    switchToMap();
                }
            });
            btCheckIn = (Button)rootView.findViewById(R.id.btCheckIn);
            btCheckIn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    switchToCheckIn();
                }
            });
            btGetLocation = (Button) rootView.findViewById(R.id.btGetLocation);
            btGetLocation.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    showCurrentLocation();
                }
            });
            return rootView;
        }
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            location = ((MainActivity)getActivity()).locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if(location==null)
            {
                location = ((MainActivity)getActivity()).locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            }
        }
        private void switchToMap()
        {
            Intent i = new Intent(getActivity(), MapsActivity.class);
            Bundle b = new Bundle();
            if(location!=null)
            {
            b.putDouble("longitude", location.getLongitude());
            b.putDouble("latitude", location.getLatitude());
            Log.v("info", "The lat "+location.getLatitude());
            Log.v("info", "The lng "+location.getLongitude());
            i.putExtras(b);
            startActivity(i);
            }else
            {
                Toast.makeText(getActivity(), "Nyalakan lokasimu", Toast.LENGTH_LONG).show();
            }
        }
        public void switchToCheckIn()
        {
            //not yet implemented
        }
        protected void showCurrentLocation() {
            if (location != null) {
                String message = String.format(
                        "Lokasi saat ini \n Longitude: %1$s \n Latitude: %2$s",
                        location.getLongitude(), location.getLatitude()
                );
                Toast.makeText(getActivity(), message,
                        Toast.LENGTH_LONG).show();
                }
        }
    }
}
Kelas MainActivity.java berfungsi sebagai driver yang mengarahkan tombol-tombol di main menu ke activity yang sesuai. Perbedaan dengan aplikasi LBS sebelumnya, kelas ini diimplementasikan menggunakan arsitektur Fragment sehingga MainActivity sebenarnya hanyalah kelas container, dan fungsi-fungsi yang digunakan ada di dalam Fragment yang bernama “PlaceholderFragment”.

Selebihnya, kelas ini juga berfungsi untuk mendeteksi lokasi user, seperti di postingan LBS yang lama. Untuk bisa mendeteksi lokasi, pertama-tama kita harus menginstansiasi kelas Location Manager yang berfungsi untuk mengakses location services, location manager akan diturunkan dari kelas parent Context dan didapatkan lewat method getSystemService() . Kemudian kita meminta update lokasi dari perangkat menggunakan method requestLocationUpdates(), pada method itu kita akan menggunakan beberapa parameter, yaitu jenis provider layanan lokasi yang diinginkan (pada kasus ini adalah layanan GPS), kemudian interval minimum untuk pemberitahuan (dalam milisekon), jarak minimun untuk pemberitahuan (dalam meter), dan yang terakhir adalah sebuah kelas yang mengimplementasikan LocationListener. Location Listener seperti yang telah dijelaskan di atas, berfungsi untuk memantau perubahan pada lokasi pengguna dan juga perubahan pada status provider.

Interface LocationListener diimplementasikan ke dalam inner class bernama MyLocationListener, pada kelas tersebut terdapat methods yang berfungsi untuk menghandle event apabila terjadi perubahan pada lokasi user atau perubahan pada status provider, dalam kasus ini kita hanya akan menampilkan Toast yang berisikan info. Kemudian apabila kita mengeklik tombol GetLocation, maka method showCurrentLocation() akan dieksekusi. Method itu akan memanggil getLastKnownLocation() dari kelas LocationManager yang akan memberikan Location terakhir yang terdeteksi. Dari object Location tersebut, kita akan dapat mengetahui parameter-parameter seperti latitude, longitude, altitude, speed, dsb.
Kemudian tombol satunya lagi adalah tombol View On Map, yang akan memunculkan lokasi kita pada Android Maps. Ketika tombol tersebut di-klik, informasi lokasi seperti latitude dan longitude, akan dimasukkan ke dalam sebuah Bundle, info itu akan di-pack dan diikutkan sebagai sebuah extra pada Intent, yang nantinya akan diteruskan ke Activity selanjutnya, yaitu Activity MapsActivity.java.
Activity MapsActivity pada dasarnya tidak jauh berbeda dengan yang pernah saya tuliskan di tutorial untuk menampilkan marker koordinat pengguna. Kita hanya perlu menambahkan beberapa baris kode yang berfungsi untuk meng-unpack koordinat yang tadi diikutsertakan pada Bundle dari aktivitas sebelumnya, dan mengaplikasikan koordinat tersebut pada peta, berikut ini kode lengkapnya :
MapsActivity.java
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package id.web.twoh.twohmaps;
import java.util.ArrayList;
import id.web.twoh.twohmaps.R;
import id.web.twoh.twohmaps.model.DBLokasi;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;
public class MapsActivity extends FragmentActivity{
    private GoogleMap map;
    private DBLokasi lokasi;
    private ArrayList<DBLokasi> values;
    @SuppressWarnings("unchecked")
    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.activity_map);
        SupportMapFragment mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        map = mapFrag.getMap();
        map.setMyLocationEnabled(true);
        Bundle b = this.getIntent().getExtras();
        if(b.containsKey("longitude")){
            final LatLng latLng = new LatLng(b.getDouble("latitude"), b.getDouble("longitude"));
            map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16));
            map.addMarker(new MarkerOptions().position(latLng).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_CYAN)));
            map.setOnMarkerClickListener(new OnMarkerClickListener() {
                @Override
                public boolean onMarkerClick(Marker marker) {
                    Toast.makeText(MapsActivity.this, "Lokasi saat ini "+latLng.latitude+","+latLng.longitude,Toast.LENGTH_SHORT).show();
                    return false;
                }
            });
        }else if(this.getIntent().getSerializableExtra("lokasi")!=null)
        {
            lokasi = (DBLokasi) this.getIntent().getSerializableExtra("lokasi");
            if(lokasi!=null)
            {
                LatLng latLng = new LatLng(lokasi.getLatD(), lokasi.getLngD());
                map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16));
                map.addMarker(new MarkerOptions().position(latLng).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_CYAN)));
            }
            map.setOnMarkerClickListener(new OnMarkerClickListener() {
                @Override
                public boolean onMarkerClick(Marker marker) {
                    // see next post <img src="http://i1.wp.com/www.twoh.co/wp-includes/images/smilies/icon_smile.gif?w=955" alt=":)" class="wp-smiley" height="15" width="15">
                    return false;
                }
            });
        }else
        {
            LatLng init;
            DBLokasi lokInit;
            LatLng latLng;
            values = ((ArrayList<DBLokasi>) this.getIntent().getSerializableExtra("arraylokasi"));
            lokInit = values.get(0);
            init = new LatLng(lokInit.getLatD(), lokInit.getLngD());
            map.animateCamera(CameraUpdateFactory.newLatLngZoom(init, 16));
            for(DBLokasi lok : values)
            {
                latLng = new LatLng(lok.getLatD(), lok.getLngD());
                map.addMarker(new MarkerOptions().position(latLng).icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_CYAN)));
            }
            map.setOnMarkerClickListener(new OnMarkerClickListener() {
                @Override
                public boolean onMarkerClick(Marker marker) {
                    // see next post <img src="http://i1.wp.com/www.twoh.co/wp-includes/images/smilies/icon_smile.gif?w=955" alt=":)" class="wp-smiley" height="15" width="15">
                    return false;
                }
            });
        }
    }
}
Kemudian untuk layout xml yang digunakan pada activity MapsActivity tersebut, buatlah sebuah file xml layout bernama activity_map.xml, dan isikan kode berikut :
activity_map.xml
?
01
02
03
04
05
06
07
08
09
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <fragment
          android:id="@+id/map"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:name="com.google.android.gms.maps.SupportMapFragment"/>
</LinearLayout>

Yang membedakan dengan membuat layanan berbasis lokasi menggunakan MapsV1 adalah, kita tidak perlu menggunakan kelas MapsOverlay untuk menampilkan marker. Semuanya sudah dihandle pada kelas MapsActivity.java.
Dan ini adalah tampilan aplikasi ketika dijalankan, oh iya jangan lupa bahwa tutorial ini hanya bisa dijalankan di device Android langsung, dan tidak bisa dijalankan di emulator Android. Sehingga pastikan kalian mencobanya di smartphone Android.

Demo

Ketika tombol “Get Location” diklik :

Get Current User Location

Get Current User Location

Klik “View On Map” untuk membuat visualisasi dari lokasi dimana kalian berada B-)


View On Map v2

View On Map v2

Dan inilah yang muncul ketika kalian klik pada Marker :

Click on Marker

Click on Marker


Oke, seperti kira-kira seperti itu. Jika masih ada yang bingung silahkan bertanya di bagian komentar. Untuk source code-nya bisa diambil di GitHub saya. Semoga membantu.

Sumber : http://www.twoh.co/2014/08/membuat-aplikasi-location-based-services-di-android-menggunakan-maps-api-v2

1 komentar:

  1. saya mengalami error di src nya mas, rata2 error semuanya di MainActivity, MapsActivity dan di res bagian values.. mohon pencerahannya

    BalasHapus