Recommended lifecycle of various mapsforge components?

84 views
Skip to first unread message

Kees van Reeuwijk

unread,
Mar 6, 2016, 4:24:49 PM3/6/16
to mapsforge-dev
Hello,

Sorry if this seems a bit elementary, but I'd like to understand some of the design decisions and assumptions that were made for mapsforge. The background is that I have an Android app (imagine something similar to a Garmin or Magellan handheld GPS) that provides multiple screens with navigation info, and some of these pages have a MapView somewhere among other Views. Potentially a single screen can even have more than one MapView, although that's not particularly useful, since every instance will always show the same map location, zoom, and style. The user can quickly switch between the various screens, and MapView instances are destroyed and created to implement this. Thus, creating and destroying MapView instances will be a regular occurrence. 

Now, what should the lifecycle of the various mapsforge components be? I'll list the components, and what I think makes sense, but I'd love to be corrected if I'm for some reason wrong.

* Map data
I'm assuming that the user has a folder somewhere with vector maps, and I'll build a MultiMapDataStore from all the maps I can find in that folder. I imagine it makes most sense to build a MultiMapDataStore in the onCreate() of the app that covers all the map files I have available. As far as I can tell I only have to call close() on the instance to destroy it, and I only have to do that in onDestroy(). I'm guessing that the data of the MultiMapDataStore is not large enough that it is worth calling close() on it in an onPause(), and then build it again in onResume(). As far as I can tell, there is no reason to create a new MultiMapDataStore every time I create a new MapView.

If I need to store the maps on an external SD card, the lifecycle of the MultiMapDataStore should be coupled to the availability of the SD card.

* LayerManager, Layers, individual layers

Since all MapView instances will always show the same info, conceptually it would be possible to have only a single LayerManager with the same lifecycle as the map data or the render theme (see below), but as far as I can tell, it is not possible to let multiple MapViews share a single LayerManager, or to `transplant' a LayerManager from one MapView to the next one. The same applies for instances of the Layers class, or instances of individual layers.

* In-memory tile cache
The most obvious lifetime of the in-memory tile cache is from onResume() to onPause(), but it seems to me that caches are directly coupled to a particular map view instance/Layer, and then I'll have to destroy the cache every time a view is destroyed, even if the user switches from one page with a map view to another page with a map view.

* External tile cache
The most obvious lifetime of the external tile cache is `as long as the app is installed, or until a map file is replaced', but again I'm not sure that is really possible.

* Render themes
Another complication is that I'd like to let the user switch between different render themes. At the very least I'll need to use different caches for the different render themes, although again I'm afraid I'll have to destroy all caches on every switch.

Am I missing a component?

Thanks for clarification on all these issues!

-- 
Kees van Reeuwijk

Emux

unread,
Mar 7, 2016, 2:39:31 AM3/7/16
to mapsfo...@googlegroups.com
I recommend to check our Getting-Started-Android-App guide and additionally the various examples of Mapsforge use at the Samples app.

There you can see the life cycle of the map view in actual code.
Essentially everything painted on its own Layer (vector tiles, overlays, etc).
And you can have multiple map views showing different maps (aka layers).

Again there is ready code in Samples for various scenarios (all you described).
The easiest way it to study the examples and check the code implementations.

--
Emux

Ludwig

unread,
Mar 7, 2016, 4:19:41 AM3/7/16
to mapsfo...@googlegroups.com
In addition to Emux' comment, I have a few specific notes to your questions (which I think are good and legitimate):

Android's main unit of resource management is the activity, not really a view. You do not really say if your switching between different map views will be within one activity or whether this will also mean a switch of activities. Basically, when using activities, regardless of your application, you can never be sure that its resources will not be recycled when stopped. 
 
* Map data
I'm assuming that the user has a folder somewhere with vector maps, and I'll build a MultiMapDataStore from all the maps I can find in that folder. I imagine it makes most sense to build a MultiMapDataStore in the onCreate() of the app that covers all the map files I have available. As far as I can tell I only have to call close() on the instance to destroy it, and I only have to do that in onDestroy(). I'm guessing that the data of the MultiMapDataStore is not large enough that it is worth calling close() on it in an onPause(), and then build it again in onResume(). As far as I can tell, there is no reason to create a new MultiMapDataStore every time I create a new MapView.

To me the answer to this question depends a bit on the complexity the MultiMapDataStore. There are two aspects to it:
  • Building it: if you envision users with many map files (or other map data sources) that are complex to open, then there might be a point of building the MultiMapDataStore independently of activities and certainly views. You you build up your MultiMapDataStore at application startup somewhere in the ApplicationContext and reference it a some sort of global context. 
  • Querying it: our implementation of the query is simple and might be much too slow if many maps are involved as every single map might be queried for every tile (depending on settings) You might want to implement your own mechanism to optimize this. 
If I need to store the maps on an external SD card, the lifecycle of the MultiMapDataStore should be coupled to the availability of the SD card.

Easier said then done. 
 

* LayerManager, Layers, individual layers

Since all MapView instances will always show the same info, conceptually it would be possible to have only a single LayerManager with the same lifecycle as the map data or the render theme (see below), but as far as I can tell, it is not possible to let multiple MapViews share a single LayerManager, or to `transplant' a LayerManager from one MapView to the next one. The same applies for instances of the Layers class, or instances of individual layers.

I think the LayerManager is actually pretty cheap, so there is no harm to have one for every view. 
 

* In-memory tile cache
The most obvious lifetime of the in-memory tile cache is from onResume() to onPause(), but it seems to me that caches are directly coupled to a particular map view instance/Layer, and then I'll have to destroy the cache every time a view is destroyed, even if the user switches from one page with a map view to another page with a map view.

Each view has an unnamed in-memory cache and as backing can have a persistent cache. I think it might be possible to share the in-memory cache somehow, the changes required might not be so dramatic. 
 

* External tile cache
The most obvious lifetime of the external tile cache is `as long as the app is installed, or until a map file is replaced', but again I'm not sure that is really possible.

There is a mechanism that ties the life-time of tiles in the persistent cache to the timestamp of the map. 
 

* Render themes
Another complication is that I'd like to let the user switch between different render themes. At the very least I'll need to use different caches for the different render themes, although again I'm afraid I'll have to destroy all caches on every switch.

The persistent cache could be tied to a particular rendertheme, the in-memory tile-cache not. 
 

Hope this helps

Ludwig

Emux

unread,
Mar 7, 2016, 4:33:20 AM3/7/16
to mapsfo...@googlegroups.com
To clarify a bit Ludwig's nice remarks, file cache can be persistent or not.

But if map model changes then usually the cache has to be re-initialized.

Map model can change by many things, like different render theme, a new tile size, etc.
The Samples examples (e.g. RenderThemeChanger) show where a map change requires a new cache.

--
Emux

Kees van Reeuwijk

unread,
Mar 7, 2016, 5:18:48 PM3/7/16
to mapsforge-dev


On Monday, March 7, 2016 at 10:19:41 AM UTC+1, Ludwig wrote:
In addition to Emux' comment, I have a few specific notes to your questions (which I think are good and legitimate):

Of course I've looked at the examples, and they are helpful, but the fundamental problem of examples is that they only show one way of using the software, and not the general concepts behind them. That's what I'm trying to discover here.

 
Android's main unit of resource management is the activity, not really a view. You do not really say if your switching between different map views will be within one activity or whether this will also mean a switch of activities. Basically, when using activities, regardless of your application, you can never be sure that its resources will not be recycled when stopped. 

Of course. What I'm talking about is essentially a single Application instance that has tabs. During the lifetime of the Application, the MapViews in these tabs will be created and destroyed repeatedly (keeping all views alive is probably too expensive, especially if they can't share anything).


* Map data
I'm assuming that the user has a folder somewhere with vector maps, and I'll build a MultiMapDataStore from all the maps I can find in that folder. I imagine it makes most sense to build a MultiMapDataStore in the onCreate() of the app that covers all the map files I have available. As far as I can tell I only have to call close() on the instance to destroy it, and I only have to do that in onDestroy(). I'm guessing that the data of the MultiMapDataStore is not large enough that it is worth calling close() on it in an onPause(), and then build it again in onResume(). As far as I can tell, there is no reason to create a new MultiMapDataStore every time I create a new MapView.

To me the answer to this question depends a bit on the complexity the MultiMapDataStore. There are two aspects to it:
  • Building it: if you envision users with many map files (or other map data sources) that are complex to open, then there might be a point of building the MultiMapDataStore independently of activities and certainly views. You you build up your MultiMapDataStore at application startup somewhere in the ApplicationContext and reference it a some sort of global context. 
  • Querying it: our implementation of the query is simple and might be much too slow if many maps are involved as every single map might be queried for every tile (depending on settings) You might want to implement your own mechanism to optimize this. 

For now I'm assuming the user just has map files for a few countries or regions of interest, say 10 non-overlapping maps. There is a bounding box in each map, and you're looking at those, no? So that shouldn't be much more expensive than loading individual maps directly, right?

 
If I need to store the maps on an external SD card, the lifecycle of the MultiMapDataStore should be coupled to the availability of the SD card.

Easier said then done. 

Agreed, I've done both. :-) But it is possible. I have done it. It does complicate the management of those MapViews, though.

 

* LayerManager, Layers, individual layers

Since all MapView instances will always show the same info, conceptually it would be possible to have only a single LayerManager with the same lifecycle as the map data or the render theme (see below), but as far as I can tell, it is not possible to let multiple MapViews share a single LayerManager, or to `transplant' a LayerManager from one MapView to the next one. The same applies for instances of the Layers class, or instances of individual layers.

I think the LayerManager is actually pretty cheap, so there is no harm to have one for every view. 

I'm not so much interested in reusing or sharing the list datastructures, but rather the individual layers. Sharing an entire stack of layers through a single LayerManager is just the easiest way to do so.
 
 

* In-memory tile cache
The most obvious lifetime of the in-memory tile cache is from onResume() to onPause(), but it seems to me that caches are directly coupled to a particular map view instance/Layer, and then I'll have to destroy the cache every time a view is destroyed, even if the user switches from one page with a map view to another page with a map view.

Each view has an unnamed in-memory cache and as backing can have a persistent cache. I think it might be possible to share the in-memory cache somehow, the changes required might not be so dramatic. 

Ah, interesting. At the moment I'm providing each MapView with both an in-memory cache and a persistent cache. So that's not necessary, it seems.

However, I would be interested in a way to keep that in-memory cache alive when I destroy a MapView, and then give it to a new MapView instance.
 
 

* External tile cache
The most obvious lifetime of the external tile cache is `as long as the app is installed, or until a map file is replaced', but again I'm not sure that is really possible.

There is a mechanism that ties the life-time of tiles in the persistent cache to the timestamp of the map. 

Great, good to know! 

 

* Render themes
Another complication is that I'd like to let the user switch between different render themes. At the very least I'll need to use different caches for the different render themes, although again I'm afraid I'll have to destroy all caches on every switch.

The persistent cache could be tied to a particular rendertheme, the in-memory tile-cache not. 

Render themes are the biggest headache for me, and despite staring at the examples I've not been able to have them working reliably. Unfortunately, I'm doing this in my free time, which doesn't help.
 

 
 Hope this helps

It sure does, thanks!
 
Reply all
Reply to author
Forward
0 new messages