Added map, JSON requests and clusters

This commit is contained in:
Vladislav Khorev 2017-06-10 01:42:49 +03:00
parent 41d331da02
commit f0136fb2d3
12 changed files with 347 additions and 36 deletions

View File

@ -31,4 +31,6 @@ dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
implementation 'com.google.android.gms:play-services-maps:10.2.1' implementation 'com.google.android.gms:play-services-maps:10.2.1'
implementation 'com.google.android.gms:play-services-location:10.2.1' implementation 'com.google.android.gms:play-services-location:10.2.1'
compile 'com.google.maps.android:android-maps-utils:0.4+'
compile 'com.koushikdutta.ion:ion:2.+'
} }

View File

@ -29,7 +29,7 @@
android:value="@string/google_maps_key" /> android:value="@string/google_maps_key" />
<activity <activity
android:name=".MapsActivity" android:name=".YelpMapActivity"
android:label="@string/title_activity_maps"> android:label="@string/title_activity_maps">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@ -0,0 +1,50 @@
package fishrungames.yelpmapapp
import android.content.Context
import com.google.gson.JsonArray
import com.koushikdutta.ion.Ion
import java.io.BufferedInputStream
import java.net.HttpURLConnection
import java.net.URL
import java.security.AccessController.getContext
import com.google.gson.JsonObject
import com.koushikdutta.async.future.FutureCallback
import android.os.AsyncTask
import org.json.JSONObject
/**
* Created by mephi on 09.06.2017.
*/
class DataProvider(val context: Context, val onUpdateMapMarkers : ((Map<String, MapMarkerRecord>) -> Unit)) {
val yelpApiKey = "TFhv6H25FV25ETpIC64TmN1sZ98yLIK3-4IZ7-CFSaRIyO6Xo97n1uI5207vo3JA-gLgu1f_7dw4LLWrpAcVAELSVFwHxYDL2FEfwaheJ9WvjbgEbjd3ADWAkt46WXYx"
fun requestData(lat : Double, lon : Double, radius : Int)
{
Ion.with(context)
.load("https://api.yelp.com/v3/businesses/search?latitude=${lat}&longitude=${lon}&radius=${radius}")
.addHeader("Authorization", "Bearer " + yelpApiKey)
.asJsonObject()
.setCallback { e, result ->
if (e != null)
{
return@setCallback
}
if (result == null)
{
return@setCallback
}
HandleResponseAsyncTask(onUpdateMapMarkers).execute(result)
};
}
}

View File

@ -0,0 +1,52 @@
package fishrungames.yelpmapapp
import android.os.AsyncTask
import com.google.gson.JsonObject
/**
* Created by mephi on 10.06.2017.
*/
class HandleResponseAsyncTask(val onUpdateMapMarkers : ((Map<String, MapMarkerRecord>) -> Unit)) : AsyncTask<JsonObject, Int, Map<String, MapMarkerRecord>>()
{
override fun doInBackground(vararg response : JsonObject): Map<String, MapMarkerRecord> {
val newMapMarkers = mutableMapOf<String, MapMarkerRecord>()
try {
for (businessElement in response[0].getAsJsonArray("businesses")) {
val businessJson = businessElement.asJsonObject
val id = businessJson.get("id").asString
val name = businessJson.get("name").asString
val image_url = businessJson.get("image_url").asString
val latitude = businessJson.get("coordinates").asJsonObject.get("latitude").asDouble
val longitude = businessJson.get("coordinates").asJsonObject.get("longitude").asDouble
var mapMarker = MapMarkerRecord(id, name, image_url, latitude, longitude)
newMapMarkers[name] = mapMarker
}
}
catch (e : Exception)
{
e.printStackTrace()
}
return newMapMarkers
}
override fun onPostExecute(result: Map<String, MapMarkerRecord>) {
super.onPostExecute(result)
onUpdateMapMarkers(result)
}
}

View File

@ -0,0 +1,21 @@
package fishrungames.yelpmapapp
import com.google.maps.android.clustering.ClusterItem
import com.google.android.gms.maps.model.LatLng
/**
* Created by mephi on 10.06.2017.
*/
class MapMarkerClusterItem(inMapMarkerRecord : MapMarkerRecord) : ClusterItem
{
private val mPosition = LatLng(inMapMarkerRecord.lat, inMapMarkerRecord.lon)
val mapMarkerRecord = inMapMarkerRecord
override fun getPosition(): LatLng {
return mPosition
}
}

View File

@ -0,0 +1,14 @@
package fishrungames.yelpmapapp
/**
* Created by mephi on 09.06.2017.
*/
data class MapMarkerRecord (
val id: String,
val name: String,
val imageUrl: String,
val lat: Double,
val lon: Double
)

View File

@ -27,11 +27,11 @@ import android.content.DialogInterface
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener, open class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener { GoogleApiClient.OnConnectionFailedListener {
private var mMap: GoogleMap? = null internal var mMap: GoogleMap? = null
private var mLastLocation: Location? = null private var mLastLocation: Location? = null
@ -61,22 +61,20 @@ class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener,
override fun onMapReady(googleMap: GoogleMap) { override fun onMapReady(googleMap: GoogleMap) {
// Add a marker in Sydney and move the camera // Add a marker in Sydney and move the camera
val sydney = LatLng(-34.0, 151.0) //val sydney = LatLng(-34.0, 151.0)
googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney")) //googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney)) //googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
if (ContextCompat.checkSelfPermission(this, if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
Manifest.permission.ACCESS_FINE_LOCATION) //Location Permission already granted
== PackageManager.PERMISSION_GRANTED) { buildGoogleApiClient()
//Location Permission already granted googleMap.isMyLocationEnabled = true
buildGoogleApiClient() } else {
googleMap.setMyLocationEnabled(true) //Request Location Permission
} else { checkLocationPermission()
//Request Location Permission }
checkLocationPermission()
}
mMap = googleMap mMap = googleMap
@ -85,11 +83,13 @@ class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener,
override fun onConnected(bundle: Bundle?) { override fun onConnected(bundle: Bundle?) {
val locationRequest = LocationRequest() val locationRequest = LocationRequest()
locationRequest.setInterval(1000)
locationRequest.setFastestInterval(1000) locationRequest.interval = 1000
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) locationRequest.fastestInterval = 1000
if (ContextCompat.checkSelfPermission(this, locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, this) LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, this)
} }
@ -101,18 +101,14 @@ class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener,
override fun onConnectionFailed(connectionResult: ConnectionResult) {} override fun onConnectionFailed(connectionResult: ConnectionResult) {}
override fun onLocationChanged(location: Location) { override fun onLocationChanged(location: Location) {
mLastLocation = location
//Place current location marker if (mLastLocation == null) {
val latLng = LatLng(location.latitude, location.longitude) val latLng = LatLng(location.latitude, location.longitude)
/*
val markerOptions = MarkerOptions()
markerOptions.position(latLng)
markerOptions.title("Current Position")
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))
mCurrLocationMarker = mGoogleMap.addMarker(markerOptions)*/
mMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 11f)) mLastLocation = location
mMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 11f))
}
} }
@ -187,6 +183,3 @@ class MapsActivity : FragmentActivity(), OnMapReadyCallback, LocationListener,
} }
} }
class LocationRequest {
}

View File

@ -0,0 +1,32 @@
package fishrungames.yelpmapapp
import android.app.Activity
import android.content.Context
import android.view.View
import com.google.android.gms.maps.model.Marker
import android.widget.TextView
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter
/**
* Created by mephi on 10.06.2017.
*/
internal class MyInfoWindowAdapter(val activity: Activity) : InfoWindowAdapter {
private val myContentsView: View = activity.layoutInflater.inflate(R.layout.yelp_info_contents, null)
override fun getInfoContents(marker: Marker): View {
//myContentsView.findViewById(R.id.title) = marker.title
//myContentsView.findViewById(R.id.snippet).text = marker.snippet
return myContentsView
}
override fun getInfoWindow(marker: Marker): View? {
return null
}
}

View File

@ -0,0 +1,141 @@
package fishrungames.yelpmapapp
import android.location.Location
import android.os.Handler
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.gms.maps.model.LatLng
import java.util.*
import com.google.maps.android.clustering.ClusterManager
import com.google.android.gms.maps.CameraUpdateFactory
/**
* Created by mephi on 09.06.2017.
*/
class YelpMapActivity : MapsActivity()
{
val handler = Handler()
val dataProvider = DataProvider(this, this::handleMarkersUpdated)
private var mClusterManager: ClusterManager<MapMarkerClusterItem>? = null
val markerMap = mutableMapOf<String, MapMarkerClusterItem>()
var latestRequestDate : Date? = null
var requestScheduled : Boolean = false
override fun onMapReady(googleMap: GoogleMap) {
super.onMapReady(googleMap)
googleMap.setOnCameraMoveListener {
tryRequestData(googleMap.cameraPosition.target.latitude, googleMap.cameraPosition.target.longitude)
}
setUpClusterer(googleMap)
}
override fun onLocationChanged(location: Location) {
super.onLocationChanged(location)
tryRequestData(location.latitude, location.longitude)
}
fun handleMarkersUpdated(newMarkerMap: Map<String, MapMarkerRecord>)
{
if (mClusterManager == null)
{
return
}
val clusterManager = mClusterManager!!
for (key in newMarkerMap.keys)
{
if (!markerMap.containsKey(key))
{
val mapMarkerRecord = newMarkerMap[key] as MapMarkerRecord
val mapMarkerClusterItem = MapMarkerClusterItem(mapMarkerRecord)
clusterManager.addItem(mapMarkerClusterItem)
markerMap[key] = mapMarkerClusterItem
}
}
}
fun tryRequestData(lat : Double, lon : Double) {
val requestLimitInMs = 2000L
val newDate = Date()
if (latestRequestDate == null)
{
innerRequestData(lat, lon)
}
else {
if (!requestScheduled) {
requestScheduled = true
val timeDiffMs = newDate.time - latestRequestDate!!.time
if (timeDiffMs > requestLimitInMs) {
innerRequestData(lat, lon)
} else {
handler.postDelayed({ innerRequestData(lat, lon) }, requestLimitInMs - timeDiffMs)
}
}
}
}
fun innerRequestData(lat : Double, lon : Double)
{
val radius = 2000
latestRequestDate = Date()
dataProvider.requestData(lat, lon, radius)
requestScheduled = false
}
private fun setUpClusterer(googleMap: GoogleMap) {
// Initialize the manager with the context and the map.
// (Activity extends context, so we can pass 'this' in the constructor.)
mClusterManager = ClusterManager<MapMarkerClusterItem>(this, googleMap)
// Point the map's listeners at the listeners implemented by the cluster
// manager.
googleMap.setOnCameraIdleListener(mClusterManager)
googleMap.setOnMarkerClickListener(mClusterManager)
}
}

View File

@ -5,4 +5,4 @@
android:name="com.google.android.gms.maps.SupportMapFragment" android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="fishrungames.yelpmapapp.MapsActivity" /> tools:context="fishrungames.yelpmapapp.YelpMapActivity" />

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

View File

@ -1,4 +1,4 @@
<resources> <resources>
<string name="app_name">YelpMapApp</string> <string name="app_name">YelpMapApp</string>
<string name="title_activity_maps">Map</string> <string name="title_activity_maps">Yelp Map App</string>
</resources> </resources>