From de3528baab3211677de77116b18de06503761038 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Sat, 18 Jul 2020 23:55:01 +0900 Subject: [PATCH] (possible) optimization when locating entries --- lib/model/source/location.dart | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/model/source/location.dart b/lib/model/source/location.dart index c2ea53c8d..dfa0d7bea 100644 --- a/lib/model/source/location.dart +++ b/lib/model/source/location.dart @@ -4,6 +4,7 @@ import 'package:aves/model/metadata_db.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; +import 'package:tuple/tuple.dart'; mixin LocationMixin on SourceBase { static const _commitCountThreshold = 50; @@ -24,16 +25,34 @@ mixin LocationMixin on SourceBase { Future locateEntries() async { // final stopwatch = Stopwatch()..start(); - final todo = rawEntries.where((entry) => entry.hasGps && !entry.isLocated).toList(); + final byLocated = groupBy(rawEntries.where((entry) => entry.hasGps), (entry) => entry.isLocated); + final todo = byLocated[false] ?? []; if (todo.isEmpty) return; + // cache known locations to avoid querying the geocoder unless necessary + // measuring the time it takes to process ~3000 coordinates (with ~10% of duplicates) + // does not clearly show whether it is an actual optimization, + // as results vary wildly (durations in "min:sec"): + // - with no cache: 06:17, 08:36, 08:34 + // - with cache: 08:28, 05:42, 08:03, 05:58 + // anyway, in theory it should help! + final knownLocations = , AddressDetails>{}; + byLocated[true]?.forEach((entry) => knownLocations.putIfAbsent(entry.latLng, () => entry.addressDetails)); + var progressDone = 0; final progressTotal = todo.length; setProgress(done: progressDone, total: progressTotal); final newAddresses = []; await Future.forEach(todo, (entry) async { - await entry.locate(background: true); + if (knownLocations.containsKey(entry.latLng)) { + entry.addressDetails = knownLocations[entry.latLng]?.copyWith(contentId: entry.contentId); + } else { + await entry.locate(background: true); + // it is intended to insert `null` if the geocoder failed, + // so that we skip geocoding of following entries with the same coordinates + knownLocations[entry.latLng] = entry.addressDetails; + } if (entry.isLocated) { newAddresses.add(entry.addressDetails); if (newAddresses.length >= _commitCountThreshold) {