Monday, November 6, 2017

Android Displaying Multiple Markers From Database

This article will share you how to displaying multiple markers from database. Like the title data latitude and longitude will get from server (Server created with PHP and MySQL).

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


<?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();
}
}
}
view raw Connection.php hosted with ❤ by GitHub
Please adjust your username, password and your database name.

JsonDisplayMarker.php


<?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();
The above class will displaying data in json. Here is the output of the above class :

{
"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"
}
view raw location.json hosted with ❤ by GitHub
See also : Create file Json Object and Array Using PHP

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
Second, name your project by filling field Application name and Company domain.

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 :

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'
}
view raw library.gradle hosted with ❤ by GitHub

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 :

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY" />
view raw metadata.xml hosted with ❤ by GitHub
AndroidManifest


Please adjust your AndroidManifest to be same as below :

<?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>
Okay, until here, you have done preparing your requirement for creating Google Maps in your application. Next we will create several java classes.

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 :


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.

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;
}
}
If you confuse with json format array and json format object, please continue read here : Create file json format array and json format object using PHP MySQL.

Class Client and Interface


The following are two classes that define the main URL (client) and its part (endpoint).

ApiClient.java


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;
}
}
view raw ApiClient.java hosted with ❤ by GitHub
if you clearly see the URL, it contains digits, right? These digits is the IP of my computer that connected with my local internet (Tethering from my phone).

ApiService.java


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();
}
view raw ApiService.java hosted with ❤ by GitHub

Class Logging Interceptors


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 :

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));
}
}
}
Okay, that's all. Running your project and hope works well.

Download project by clicking the following image 

https://github.com/griajobag/DisplayListMarkerFromDatabase

Related Posts

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 $


EmoticonEmoticon

:)
:(
hihi
:-)
:D
=D
:-d
;(
;-(
@-)
:o
:>)
(o)
:p
:-?
(p)
:-s
8-)
:-t
:-b
b-(
(y)
x-)
(h)