What is marker means?
Marker on Maps is a mark of a place on Google Maps. The main requirement in order to able to show the marker on Google maps are data latitude and longitude.
For example :
The coordinates of Badung Regency are -8.58193 (Latitude) and 115.177059 (Longitude). You also can check coordinates of your location on this web : Distancesto.
Ok, that's a short description about markers and its requirements, now i will share about creating the project.
To achieve the goal of this project, i create 2 projects, that are : 1 PHP project (for creating server) and 1 Android project (for client).
Creating Server
In this article i will create a simple server just for learning and not recommend to implementing in production project.
First you have to create your database structure and second create the php to connecting your project to your database.
Database
I only use one table. And inside the table i have inserted the data of latitude and longitude. Take a look at the following image
![]() |
Data LatLng |
PHP Project
There are two files in php project. First class for connect to database and the second class for displaying data location in JSON.
Connection.php
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
<?php | |
/** | |
* Created by PhpStorm. | |
* User: putuguna | |
* Date: 22/09/17 | |
* Time: 21:07 | |
*/ | |
class Connection { | |
function getConnection(){ | |
$host = "localhost"; | |
$username = "root"; | |
$password = ""; | |
$dbname = "mapsandroid"; | |
try{ | |
$conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password); | |
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | |
return $conn; | |
}catch (Exception $e){ | |
echo $e->getMessage(); | |
} | |
} | |
} |
JsonDisplayMarker.php
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
<?php | |
/** | |
* Created by PhpStorm. | |
* User: putuguna | |
* Date: 22/09/17 | |
* Time: 23:26 | |
*/ | |
require_once("Connection.php"); | |
class JsonDisplayMarker { | |
function getMarkers(){ | |
//buat koneksinya | |
$connection = new Connection(); | |
$conn = $connection->getConnection(); | |
//buat responsenya | |
$response = array(); | |
$code = "code"; | |
$message = "message"; | |
try{ | |
//tampilkan semua data dari mysql | |
$queryMarker = "SELECT * FROM location"; | |
$getData = $conn->prepare($queryMarker); | |
$getData->execute(); | |
$result = $getData->fetchAll(PDO::FETCH_ASSOC); | |
foreach($result as $data){ | |
array_push($response, | |
array( | |
'nama_lokasi'=>$data['namelocation'], | |
'latitude'=>$data['latitude'], | |
'longitude'=>$data['longitude']) | |
); | |
} | |
}catch (PDOException $e){ | |
echo "Failed displaying data".$e->getMessage(); | |
} | |
//buatkan kondisi jika berhasil atau tidaknya | |
if($queryMarker){ | |
echo json_encode( | |
array("data"=>$response,$code=>1,$message=>"Success") | |
); | |
}else{ | |
echo json_encode( | |
array("data"=>$response,$code=>0,$message=>"Failed displaying data") | |
); | |
} | |
} | |
} | |
$location = new JsonDisplayMarker(); | |
$location->getMarkers(); |
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
{ | |
"data":[ | |
{ | |
"nama_lokasi":"Denpasar", | |
"latitude":"-8.650000", | |
"longitude":"115.216667" | |
}, | |
{ | |
"nama_lokasi":"Buleleng", | |
"latitude":"-8.121376", | |
"longitude":"115.07818" | |
}, | |
{ | |
"nama_lokasi":"Karangasem", | |
"latitude":"-8.346593", | |
"longitude":"115.520736" | |
}, | |
{ | |
"nama_lokasi":"Tabanan", | |
"latitude":"-8.459556", | |
"longitude":"115.046599" | |
}, | |
{ | |
"nama_lokasi":"Negara", | |
"latitude":"-8.348246", | |
"longitude":"114.595536" | |
}, | |
{ | |
"nama_lokasi":"Bangli", | |
"latitude":"-8.297588", | |
"longitude":"115.354871" | |
}, | |
{ | |
"nama_lokasi":"Gianyar", | |
"latitude":"-8.424824", | |
"longitude":"115.260051" | |
}, | |
{ | |
"nama_lokasi":"Badung", | |
"latitude":"-8.58193", | |
"longitude":"115.177059" | |
} | |
], | |
"code":1, | |
"message":"Success" | |
} |
Android Project
I will create the project by using the default template of Android Studio. Fyi, i use Android Studio Versi 2.2.2, not the latest version.
First, click start a new android project.
![]() |
Create New Project |
![]() |
Name the project |
Third, select your platform, in this case just check the phone and tablet.
![]() |
Select the platform |
Fourth, select the template that you want to use. Related with this project, just select Google Maps Activity.
![]() |
Template |
Fifth, give name your activity, layout and title by filling the field Activity name, Layout name, Title.
![]() |
Attribute name |
After that, click button finish.
Library Gradle
I have added some libraries. Modify your gradle to be the same as bellow :
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
apply plugin: 'com.android.application' | |
android { | |
compileSdkVersion 25 | |
buildToolsVersion '23.0.1' | |
defaultConfig { | |
applicationId "com.putuguna.markerlocation" | |
minSdkVersion 16 | |
targetSdkVersion 25 | |
versionCode 1 | |
versionName "1.0" | |
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | |
} | |
buildTypes { | |
release { | |
minifyEnabled false | |
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
} | |
} | |
} | |
dependencies { | |
compile fileTree(include: ['*.jar'], dir: 'libs') | |
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { | |
exclude group: 'com.android.support', module: 'support-annotations' | |
}) | |
compile 'com.android.support:appcompat-v7:25.3.1' | |
//ini sudah bawaan saat membuat project google maps, jika kalian tidak membuat dari awal, silakan tambahkan saja manual | |
compile 'com.google.android.gms:play-services:11.0.4' | |
testCompile 'junit:junit:4.12' | |
//library utk retrofit | |
compile 'com.google.code.gson:gson:2.6.2' | |
compile 'com.squareup.retrofit2:retrofit:2.0.2' | |
compile 'com.squareup.retrofit2:converter-gson:2.0.2' | |
//libary for recyclerview | |
compile 'com.android.support:recyclerview-v7:25.0.0' | |
} |
Generate API_KEY
In order to able to display Google Maps in your project, you have to generate the API_KEY in Google Developer Console. You can user the existing project, or create new project.
First, generate API_KEY by clicking button GET A KEY.
![]() |
image via putuguna.com |
Second, you can use the existing project or create new project.
![]() |
image via putuguna.com |
Third, copy your API_KEY and place in meta-data androidManifest.
![]() |
image via putuguna.com |
Confuse? Take a look at the following meta-data in AndroidManifest file :
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
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY" />
AndroidManifest
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
<meta-data | |
android:name="com.google.android.geo.API_KEY" | |
android:value="YOUR_API_KEY" /> |
Please adjust your AndroidManifest to be same as below :
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
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.putuguna.markerlocation"> | |
<!-- | |
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use | |
Google Maps Android API v2, but you must specify either coarse or fine | |
location permissions for the 'MyLocation' functionality. | |
--> | |
<uses-permission android:name="android.permission.INTERNET"/> | |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | |
<application | |
android:allowBackup="true" | |
android:icon="@mipmap/ic_launcher" | |
android:label="@string/app_name" | |
android:supportsRtl="true" | |
android:theme="@style/AppTheme"> | |
<!-- | |
The API key for Google Maps-based APIs is defined as a string resource. | |
(See the file "res/values/google_maps_api.xml"). | |
Note that the API key is linked to the encryption key used to sign the APK. | |
You need a different API key for each encryption key, including the release key that is used to | |
sign the APK for publishing. | |
You can define the keys for the debug and release targets in src/debug/ and src/release/. | |
--> | |
<meta-data | |
android:name="com.google.android.geo.API_KEY" | |
android:value="YOUR_API_KEY" /> | |
<activity | |
android:name=".MapsActivity" | |
android:label="@string/title_activity_maps"> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
</application> | |
</manifest> |
Create two classes as model to handle the data from json
LocationModel.java
This class used to handle one object data from json. The code look like the follows :
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 com.putuguna.markerlocation.models; | |
import com.google.gson.annotations.SerializedName; | |
/** | |
* Created by putuguna on 30/09/17. | |
*/ | |
public class LocationModel { | |
@SerializedName("nama_lokasi") | |
private String imageLocationName; | |
@SerializedName("latitude") | |
private String latutide; | |
@SerializedName("longitude") | |
private String longitude; | |
public LocationModel(String imageLocationName, String latutide, String longitude) { | |
this.imageLocationName = imageLocationName; | |
this.latutide = latutide; | |
this.longitude = longitude; | |
} | |
public LocationModel() { | |
} | |
public String getImageLocationName() { | |
return imageLocationName; | |
} | |
public void setImageLocationName(String imageLocationName) { | |
this.imageLocationName = imageLocationName; | |
} | |
public String getLatutide() { | |
return latutide; | |
} | |
public void setLatutide(String latutide) { | |
this.latutide = latutide; | |
} | |
public String getLongitude() { | |
return longitude; | |
} | |
public void setLongitude(String longitude) { | |
this.longitude = longitude; | |
} | |
} |
ListLocationModel.java
Because json that we will receive is an array, means more than one object, then one object in class LocationModel will created as list with class ListLocationModel.
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 com.putuguna.markerlocation.models; | |
import com.google.gson.annotations.SerializedName; | |
import java.util.List; | |
/** | |
* Created by putuguna on 9/30/2017. | |
*/ | |
public class ListLocationModel { | |
@SerializedName("data") | |
private List<LocationModel> mData; | |
public ListLocationModel(List<LocationModel> mData) { | |
this.mData = mData; | |
} | |
public ListLocationModel() { | |
} | |
public List<LocationModel> getmData() { | |
return mData; | |
} | |
public void setmData(List<LocationModel> mData) { | |
this.mData = mData; | |
} | |
} |
Class Client and Interface
The following are two classes that define the main URL (client) and its part (endpoint).
ApiClient.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 com.putuguna.markerlocation.services; | |
import com.putuguna.markerlocation.LoggingInterceptor; | |
import okhttp3.OkHttpClient; | |
import retrofit2.Retrofit; | |
import retrofit2.converter.gson.GsonConverterFactory; | |
/** | |
* Created by putuguna on 30/09/17. | |
*/ | |
public class ApiClient { | |
public static final String URL = "http://192.168.43.148/MenampilkanDataKetablePHP/"; | |
public static Retrofit RETROFIT = null; | |
public static Retrofit getClient(){ | |
if(RETROFIT==null){ | |
OkHttpClient client = new OkHttpClient.Builder() | |
.addInterceptor(new LoggingInterceptor()) | |
.build(); | |
RETROFIT = new Retrofit.Builder() | |
.baseUrl(URL) | |
.client(client) | |
.addConverterFactory(GsonConverterFactory.create()) | |
.build(); | |
} | |
return RETROFIT; | |
} | |
} |
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 com.putuguna.markerlocation.services; | |
import com.putuguna.markerlocation.models.ListLocationModel; | |
import com.putuguna.markerlocation.models.LocationModel; | |
import retrofit2.Call; | |
import retrofit2.http.GET; | |
/** | |
* Created by putuguna on 30/09/17. | |
*/ | |
public interface ApiService { | |
@GET("JsonDisplayMarker.php") | |
Call<ListLocationModel> getAllLocation(); | |
} |
Class Logging Interceptors
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 com.putuguna.markerlocation; | |
import android.util.Log; | |
import java.io.IOException; | |
import okhttp3.Interceptor; | |
import okhttp3.Request; | |
import okhttp3.Response; | |
import okhttp3.ResponseBody; | |
import okio.Buffer; | |
/** | |
* Created by putuguna on 30/09/17. | |
*/ | |
public class LoggingInterceptor 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"; | |
} | |
} | |
} |
Class MainActivity
This class is the main class that used to displaying all data makers on Google Maps. The full code is show as bellow :
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 com.putuguna.markerlocation; | |
import android.app.ProgressDialog; | |
import android.support.v4.app.FragmentActivity; | |
import android.os.Bundle; | |
import android.widget.Toast; | |
import com.google.android.gms.maps.CameraUpdateFactory; | |
import com.google.android.gms.maps.GoogleMap; | |
import com.google.android.gms.maps.OnMapReadyCallback; | |
import com.google.android.gms.maps.SupportMapFragment; | |
import com.google.android.gms.maps.model.LatLng; | |
import com.google.android.gms.maps.model.MarkerOptions; | |
import com.putuguna.markerlocation.models.ListLocationModel; | |
import com.putuguna.markerlocation.models.LocationModel; | |
import com.putuguna.markerlocation.services.ApiClient; | |
import com.putuguna.markerlocation.services.ApiService; | |
import java.util.ArrayList; | |
import java.util.List; | |
import retrofit2.Call; | |
import retrofit2.Callback; | |
import retrofit2.Response; | |
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback { | |
private GoogleMap mMap; | |
private List<LocationModel> mListMarker = new ArrayList<>(); | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_maps); | |
// Obtain the SupportMapFragment and get notified when the map is ready to be used. | |
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() | |
.findFragmentById(R.id.map); | |
mapFragment.getMapAsync(this); | |
} | |
/** | |
* Manipulates the map once available. | |
* This callback is triggered when the map is ready to be used. | |
* This is where we can add markers or lines, add listeners or move the camera. In this case, | |
* we just add a marker near Sydney, Australia. | |
* If Google Play services is not installed on the device, the user will be prompted to install | |
* it inside the SupportMapFragment. This method will only be triggered once the user has | |
* installed Google Play services and returned to the app. | |
*/ | |
@Override | |
public void onMapReady(GoogleMap googleMap) { | |
mMap = googleMap; | |
getAllDataLocationLatLng(); | |
} | |
/** | |
* method ini digunakan menampilkan data marker dari database | |
*/ | |
private void getAllDataLocationLatLng(){ | |
final ProgressDialog dialog = new ProgressDialog(this); | |
dialog.setMessage("Menampilkan data marker .."); | |
dialog.show(); | |
ApiService apiService = ApiClient.getClient().create(ApiService.class); | |
Call<ListLocationModel> call = apiService.getAllLocation(); | |
call.enqueue(new Callback<ListLocationModel>() { | |
@Override | |
public void onResponse(Call<ListLocationModel> call, Response<ListLocationModel> response) { | |
dialog.dismiss(); | |
mListMarker = response.body().getmData(); | |
initMarker(mListMarker); | |
} | |
@Override | |
public void onFailure(Call<ListLocationModel> call, Throwable t) { | |
dialog.dismiss(); | |
Toast.makeText(MapsActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show(); | |
} | |
}); | |
} | |
/** | |
* Method ini digunakan untuk menampilkan semua marker di maps dari data yang didapat dari database | |
* @param listData | |
*/ | |
private void initMarker(List<LocationModel> listData){ | |
//iterasi semua data dan tampilkan markernya | |
for (int i=0; i<mListMarker.size(); i++){ | |
//set latlng nya | |
LatLng location = new LatLng(Double.parseDouble(mListMarker.get(i).getLatutide()), Double.parseDouble(mListMarker.get(i).getLongitude())); | |
//tambahkan markernya | |
mMap.addMarker(new MarkerOptions().position(location).title(mListMarker.get(i).getImageLocationName())); | |
//set latlng index ke 0 | |
LatLng latLng = new LatLng(Double.parseDouble(mListMarker.get(0).getLatutide()), Double.parseDouble(mListMarker.get(0).getLongitude())); | |
//lalu arahkan zooming ke marker index ke 0 | |
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latLng.latitude,latLng.longitude), 11.0f)); | |
} | |
} | |
} |
Download project by clicking the following image
8 komentar
Hi, I am getting the following error when I try to run the app
java.lang.IllegalArgumentException: API declarations must be interfaces.
any suggestions_
Can you help me please ? I'm trying make this with Mapbox but there's some differences
how to implement setOnInfoWindowClickListener?
how to implement setOnInfoWindowClickListener
I am getting this error
java.lang.illegalstateexception: expected begin_object but was begin_array at line 8 column 2 path $
I am getting this error
java.lang.illegalstateexception: expected begin_object but was begin_array at line 8 column 2 path $
Thanks alot..it worked
Thanks alot 😍
EmoticonEmoticon