Skip to content

Commit

Permalink
Merge branch 'evict_error_tiles' of https://github.com/maRci002/flutt…
Browse files Browse the repository at this point in the history
…er_map into maRci002-evict_error_tiles
  • Loading branch information
johnpryan committed Mar 16, 2021
2 parents 8be3c5a + 9479970 commit 6201ef9
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 6 deletions.
1 change: 1 addition & 0 deletions example/lib/pages/wms_tile_layer.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';

import '../widgets/drawer.dart';

class WMSLayerPage extends StatelessWidget {
Expand Down
79 changes: 73 additions & 6 deletions lib/src/layer/tile_layer.dart
Expand Up @@ -18,6 +18,20 @@ import 'layer.dart';

typedef TemplateFunction = String Function(
String str, Map<String, String> data);

enum EvictErrorTileStrategy {
// never evict error Tiles
none,
// evict error Tiles during _pruneTiles / _abortLoading calls
dispose,
// evict error Tiles which are not visible anymore but respect margin (see keepBuffer option)
// (Tile's zoom level not equals current _tileZoom or Tile is out of viewport)
notVisibleRespectMargin,
// evict error Tiles which are not visible anymore
// (Tile's zoom level not equals current _tileZoom or Tile is out of viewport)
notVisible,
}

typedef ErrorTileCallBack = void Function(Tile tile, dynamic error);

/// Describes the needed properties to create a tile-based layer. A tile is an
Expand Down Expand Up @@ -208,6 +222,11 @@ class TileLayerOptions extends LayerOptions {
/// There are predefined examples in 'tile_builder.dart'
final TilesContainerBuilder tilesContainerBuilder;

// If a Tile was loaded with error and if strategy isn't `none` then TileProvider
// will be asked to evict Image based on current strategy
// (see #576 - even Error Images are cached in flutter)
final EvictErrorTileStrategy evictErrorTileStrategy;

TileLayerOptions({
Key key,
this.urlTemplate,
Expand Down Expand Up @@ -249,6 +268,7 @@ class TileLayerOptions extends LayerOptions {
this.templateFunction = util.template,
this.tileBuilder,
this.tilesContainerBuilder,
this.evictErrorTileStrategy = EvictErrorTileStrategy.none,
}) : updateInterval =
updateInterval <= 0 ? null : Duration(milliseconds: updateInterval),
tileFadeInDuration = tileFadeInDuration <= 0
Expand Down Expand Up @@ -564,7 +584,8 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
var tile = _tiles[key];

tile.tileReady = null;
tile.dispose();
tile.dispose(tile.loadError &&
options.evictErrorTileStrategy != EvictErrorTileStrategy.none);
_tiles.remove(key);
}
}
Expand Down Expand Up @@ -924,6 +945,8 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
}
}

_evictErrorTilesBasedOnStrategy(tileRange);

// sort tile queue to load tiles in order of their distance to center
queue.sort((a, b) =>
(a.distanceTo(tileCenter) - b.distanceTo(tileCenter)).toInt());
Expand Down Expand Up @@ -969,7 +992,8 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
return;
}

tile.dispose();
tile.dispose(tile.loadError &&
options.evictErrorTileStrategy != EvictErrorTileStrategy.none);
_tiles.remove(key);
}

Expand All @@ -989,6 +1013,46 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
tile.loadTileImage();
}

void _evictErrorTilesBasedOnStrategy(Bounds tileRange) {
if (options.evictErrorTileStrategy ==
EvictErrorTileStrategy.notVisibleRespectMargin) {
var toRemove = <String>[];
for (var entry in _tiles.entries) {
var tile = entry.value;

if (tile.loadError && !tile.current) {
toRemove.add(entry.key);
}
}

for (var key in toRemove) {
var tile = _tiles[key];

tile.dispose(true);
_tiles.remove(key);
}
} else if (options.evictErrorTileStrategy ==
EvictErrorTileStrategy.notVisible) {
var toRemove = <String>[];
for (var entry in _tiles.entries) {
var tile = entry.value;
var c = tile.coords;

if (tile.loadError &&
(!tile.current || !tileRange.contains(CustomPoint(c.x, c.y)))) {
toRemove.add(entry.key);
}
}

for (var key in toRemove) {
var tile = _tiles[key];

tile.dispose(true);
_tiles.remove(key);
}
}
}

void _tileReady(Coords<double> coords, dynamic error, Tile tile) {
if (null != error) {
print(error);
Expand Down Expand Up @@ -1145,10 +1209,13 @@ class Tile implements Comparable<Tile> {
// call this before GC!
void dispose([bool evict = false]) {
if (evict && imageProvider != null) {
imageProvider
.evict()
.then((bool succ) => print('evict tile: $coords -> $succ'))
.catchError((error) => print('evict tile: $coords -> $error'));
try {
imageProvider.evict().catchError(print);
} catch (e) {
// this may be never called because catchError will handle errors, however
// we want to avoid random crashes like in #444 / #536
print(e);
}
}

animationController?.removeStatusListener(_onAnimateEnd);
Expand Down

0 comments on commit 6201ef9

Please sign in to comment.