Skip to content

Commit

Permalink
Add caching to protomaps tile client
Browse files Browse the repository at this point in the history
This change moves the soundscape-backend specific parts of TileClient out
into a sub-class so that a protomaps TileClient can share the caching code.

It also removes the unused http caching from MainActivity - we no longer
use the type of HTTP access that would use this cache.
  • Loading branch information
davecraig committed Oct 31, 2024
1 parent 8ee2169 commit 731c101
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,6 @@ class MainActivity : AppCompatActivity() {
return
}

// Install HTTP cache this caches all of the UI tiles (at least?)
try {
val httpCacheDir = File(applicationContext.cacheDir, "http")
val httpCacheSize = (100 * 1024 * 1024).toLong() // 100 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize)
} catch (e: IOException) {
Log.i("Injection", "HTTP response cache installation failed:$e")
}

checkAndRequestNotificationPermissions()
soundscapeServiceConnection.tryToBindToServiceIfRunning(applicationContext)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import org.scottishtecharmy.soundscape.locationprovider.DirectionProvider
import org.scottishtecharmy.soundscape.locationprovider.LocationProvider
import org.scottishtecharmy.soundscape.network.ITileDAO
import org.scottishtecharmy.soundscape.network.ProtomapsTileClient
import org.scottishtecharmy.soundscape.network.SoundscapeBackendTileClient
import org.scottishtecharmy.soundscape.network.TileClient
import org.scottishtecharmy.soundscape.utils.RelativeDirections
import org.scottishtecharmy.soundscape.utils.TileGrid
Expand Down Expand Up @@ -90,7 +91,7 @@ class GeoEngine {
private val tilesDao : TilesDao = TilesDao(tileDataRealm)
private val tilesRepository : TilesRepository = TilesRepository(tilesDao)

// HTTP connection to soundscape-backend tile server
// HTTP connection to soundscape-backend or protomaps tile server
private lateinit var tileClient : TileClient

private lateinit var locationProvider : LocationProvider
Expand All @@ -111,7 +112,12 @@ class GeoEngine {

sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application.applicationContext)

tileClient = TileClient(application)
tileClient = if(SOUNDSCAPE_TILE_BACKEND) {
SoundscapeBackendTileClient(application)
} else {
ProtomapsTileClient(application)
}

configLocale = getCurrentLocale()
configuration = Configuration(application.applicationContext.resources.configuration)
configuration.setLocale(configLocale)
Expand Down Expand Up @@ -177,11 +183,12 @@ class GeoEngine {
var ret = false
withContext(Dispatchers.IO) {
try {
val protomapsClient = ProtomapsTileClient()
val service =
tileClient.retrofitInstance?.create(ITileDAO::class.java)
val tileReq = async {
protomapsClient.getClient().getMvtTileWithCache(x, y, ZOOM_LEVEL)
service?.getVectorTileWithCache(x, y, ZOOM_LEVEL)
}
val result = tileReq.await().awaitResponse().body()
val result = tileReq.await()?.awaitResponse()?.body()
if (result != null) {
val tileFeatureCollection = vectorTileToGeoJson(x, y, result)
val tileData = processTileFeatureCollection(tileFeatureCollection, quadkey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package org.scottishtecharmy.soundscape.network
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
import vector_tile.VectorTile

interface ITileDAO {
// soundscape-backend functions
@GET("tiles/16/{x}/{y}.json")
fun getTile(
@Path("x") x: Int,
Expand All @@ -16,4 +18,19 @@ interface ITileDAO {
@Path("x") x: Int,
@Path("y") y: Int
): Call<String>

// protomaps server functions
@GET("protomaps/{z}/{x}/{y}.mvt")
fun getVectorTile(
@Path("x") x: Int,
@Path("y") y: Int,
@Path("z") z: Int
): Call<VectorTile.Tile>

@GET("protomaps/{z}/{x}/{y}.mvt")
fun getVectorTileWithCache(
@Path("x") x: Int,
@Path("y") y: Int,
@Path("z") z: Int
): Call<VectorTile.Tile>
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,19 @@
package org.scottishtecharmy.soundscape.network

import retrofit2.Call
import android.app.Application
import retrofit2.Retrofit
import retrofit2.converter.protobuf.ProtoConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
import vector_tile.VectorTile

interface IProtomapsTileDAO {
@GET("protomaps/{z}/{x}/{y}.mvt")
fun getMvtTileWithCache(
@Path("x") x: Int,
@Path("y") y: Int,
@Path("z") z: Int
): Call<VectorTile.Tile>
}
/**
* This is a retrofit client for getting tiles from our protomaps server and parsing the protobuf
* automatically as it goes
* @param x tile coordinate
* @param y tile coordinate
* @param z zoom level
*/
class ProtomapsTileClient {
class ProtomapsTileClient(application: Application) : TileClient(application) {

private var retrofitInstance : Retrofit? = null
fun getClient(): IProtomapsTileDAO {
if(retrofitInstance == null) {
retrofitInstance = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ProtoConverterFactory.create())
.build()
}
return retrofitInstance!!.create(IProtomapsTileDAO::class.java)
override fun buildRetrofit() : Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ProtoConverterFactory.create())
.client(okHttpClient)
.build()
}

companion object {
private const val BASE_URL = "https://d1wzlzgah5gfol.cloudfront.net"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.scottishtecharmy.soundscape.network

import android.app.Application
import retrofit2.Retrofit
import retrofit2.converter.scalars.ScalarsConverterFactory

class SoundscapeBackendTileClient(application: Application) : TileClient(application) {

override fun buildRetrofit() : Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
// use it to output the string
.addConverterFactory(ScalarsConverterFactory.create())
.client(okHttpClient)
.build()
}

companion object {
private const val BASE_URL = "https://soundscape.scottishtecharmy.org"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ import android.net.NetworkCapabilities
import okhttp3.Cache
import okhttp3.CacheControl
import okhttp3.OkHttpClient
// import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.util.concurrent.TimeUnit

// TODO I want to get to the Cache class which is described in these articles:
// https://medium.com/@malikshahbaz213/fech-cache-api-data-in-android-kotlin-using-retrofit-91f83f36cde3
// https://stackoverflow.com/questions/70711512/context-getapplicationcontext-on-a-null-object-when-using-okhttp-cache
//https://proandroiddev.com/increase-performance-of-your-app-by-caching-api-calls-using-okhttp-1384a621c51f
// https://stackoverflow.com/questions/23429046/can-retrofit-with-okhttp-use-cache-data-when-offline?noredirect=1&lq=1
class TileClient(val application: Application) {
abstract class TileClient(val application: Application) {

private val connectivityManager: ConnectivityManager
init {
Expand All @@ -30,7 +28,7 @@ class TileClient(val application: Application) {
private val cacheSize = (5 * 1024 * 1024).toLong() //5MB cache size
private val myCache = Cache(application.applicationContext.cacheDir, cacheSize)

private val okHttpClient = OkHttpClient.Builder()
protected val okHttpClient = OkHttpClient.Builder()
.cache(myCache)
.addInterceptor { chain ->

Expand Down Expand Up @@ -66,17 +64,20 @@ class TileClient(val application: Application) {
})*/
.build()

/**
* buildRetrofit is called in the sub-class and is responsible for creating the correct type
* of Retrofit object. The SoundscapeBackendTiledClient returns a String type and the
* ProtomapsTileClient returns a VectorTile. That and the differing server URLs is taken care
* of in buildRetrofit.
*/
abstract fun buildRetrofit() : Retrofit

val retrofitInstance : Retrofit?
get() {
// has this object been created yet?
if (retrofit == null) {
// create it
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
// use it to output the string
.addConverterFactory(ScalarsConverterFactory.create())
.client(okHttpClient)
.build()
retrofit = buildRetrofit()
}
return retrofit
}
Expand All @@ -93,11 +94,4 @@ class TileClient(val application: Application) {
else -> false
}
}

companion object {
private const val BASE_URL = "https://soundscape.scottishtecharmy.org"
}

}


0 comments on commit 731c101

Please sign in to comment.