minimized change notifications, fixed logs

This commit is contained in:
Thibault Deckers 2020-01-01 20:21:41 +09:00
parent e3e222c589
commit 03246a8df4
4 changed files with 38 additions and 30 deletions

View file

@ -19,7 +19,7 @@ class ImageCollection with ChangeNotifier {
this.groupFactor, this.groupFactor,
this.sortFactor, this.sortFactor,
}) : _rawEntries = entries { }) : _rawEntries = entries {
updateSections(); if (_rawEntries.isNotEmpty) updateSections();
} }
int get imageCount => _rawEntries.where((entry) => !entry.isVideo).length; int get imageCount => _rawEntries.where((entry) => !entry.isVideo).length;
@ -64,7 +64,7 @@ class ImageCollection with ChangeNotifier {
]); ]);
break; break;
} }
debugPrint('$runtimeType updateSections'); debugPrint('$runtimeType updateSections notifyListeners');
notifyListeners(); notifyListeners();
} }
@ -114,7 +114,7 @@ class ImageCollection with ChangeNotifier {
} }
Future<void> loadCatalogMetadata() async { Future<void> loadCatalogMetadata() async {
final start = DateTime.now(); final stopwatch = Stopwatch()..start();
final saved = await metadataDb.loadMetadataEntries(); final saved = await metadataDb.loadMetadataEntries();
_rawEntries.forEach((entry) { _rawEntries.forEach((entry) {
final contentId = entry.contentId; final contentId = entry.contentId;
@ -122,12 +122,12 @@ class ImageCollection with ChangeNotifier {
entry.catalogMetadata = saved.firstWhere((metadata) => metadata.contentId == contentId, orElse: () => null); entry.catalogMetadata = saved.firstWhere((metadata) => metadata.contentId == contentId, orElse: () => null);
} }
}); });
debugPrint('$runtimeType loadCatalogMetadata complete in ${stopwatch.elapsed.inMilliseconds}ms with ${saved.length} saved entries');
onMetadataChanged(); onMetadataChanged();
debugPrint('$runtimeType loadCatalogMetadata complete in ${DateTime.now().difference(start).inSeconds}s with ${saved.length} saved entries');
} }
Future<void> loadAddresses() async { Future<void> loadAddresses() async {
final start = DateTime.now(); final stopwatch = Stopwatch()..start();
final saved = await metadataDb.loadAddresses(); final saved = await metadataDb.loadAddresses();
_rawEntries.forEach((entry) { _rawEntries.forEach((entry) {
final contentId = entry.contentId; final contentId = entry.contentId;
@ -135,36 +135,44 @@ class ImageCollection with ChangeNotifier {
entry.addressDetails = saved.firstWhere((address) => address.contentId == contentId, orElse: () => null); entry.addressDetails = saved.firstWhere((address) => address.contentId == contentId, orElse: () => null);
} }
}); });
debugPrint('$runtimeType loadAddresses complete in ${DateTime.now().difference(start).inSeconds}s with ${saved.length} saved entries'); debugPrint('$runtimeType loadAddresses complete in ${stopwatch.elapsed.inMilliseconds}ms with ${saved.length} saved entries');
} }
Future<void> catalogEntries() async { Future<void> catalogEntries() async {
final start = DateTime.now(); final stopwatch = Stopwatch()..start();
final uncataloguedEntries = _rawEntries.where((entry) => !entry.isCatalogued).toList(); final uncataloguedEntries = _rawEntries.where((entry) => !entry.isCatalogued).toList();
if (uncataloguedEntries.isEmpty) return;
final newMetadata = <CatalogMetadata>[]; final newMetadata = <CatalogMetadata>[];
await Future.forEach<ImageEntry>(uncataloguedEntries, (entry) async { await Future.forEach<ImageEntry>(uncataloguedEntries, (entry) async {
await entry.catalog(); await entry.catalog();
newMetadata.add(entry.catalogMetadata); if (entry.isCatalogued) {
newMetadata.add(entry.catalogMetadata);
}
}); });
if (newMetadata.isEmpty) return;
await metadataDb.saveMetadata(List.unmodifiable(newMetadata)); await metadataDb.saveMetadata(List.unmodifiable(newMetadata));
onMetadataChanged(); onMetadataChanged();
debugPrint('$runtimeType catalogEntries complete in ${DateTime.now().difference(start).inSeconds}s with ${newMetadata.length} new entries'); debugPrint('$runtimeType catalogEntries complete in ${stopwatch.elapsed.inSeconds}s with ${newMetadata.length} new entries');
} }
Future<void> locateEntries() async { Future<void> locateEntries() async {
final start = DateTime.now(); final stopwatch = Stopwatch()..start();
final unlocatedEntries = _rawEntries.where((entry) => entry.hasGps && !entry.isLocated).toList(); final unlocatedEntries = _rawEntries.where((entry) => entry.hasGps && !entry.isLocated).toList();
final newAddresses = <AddressDetails>[]; final newAddresses = <AddressDetails>[];
await Future.forEach<ImageEntry>(unlocatedEntries, (entry) async { await Future.forEach<ImageEntry>(unlocatedEntries, (entry) async {
await entry.locate(); await entry.locate();
newAddresses.add(entry.addressDetails); if (entry.isLocated) {
if (newAddresses.length >= 50) { newAddresses.add(entry.addressDetails);
await metadataDb.saveAddresses(List.unmodifiable(newAddresses)); if (newAddresses.length >= 50) {
newAddresses.clear(); await metadataDb.saveAddresses(List.unmodifiable(newAddresses));
newAddresses.clear();
}
} }
}); });
await metadataDb.saveAddresses(List.unmodifiable(newAddresses)); await metadataDb.saveAddresses(List.unmodifiable(newAddresses));
debugPrint('$runtimeType locateEntries complete in ${DateTime.now().difference(start).inSeconds}s'); debugPrint('$runtimeType locateEntries complete in ${stopwatch.elapsed.inMilliseconds}ms');
} }
ImageCollection filter(bool Function(ImageEntry) filter) { ImageCollection filter(bool Function(ImageEntry) filter) {

View file

@ -143,7 +143,9 @@ class ImageEntry {
Future<void> catalog() async { Future<void> catalog() async {
if (isCatalogued) return; if (isCatalogued) return;
catalogMetadata = await MetadataService.getCatalogMetadata(this); catalogMetadata = await MetadataService.getCatalogMetadata(this);
metadataChangeNotifier.notifyListeners(); if (catalogMetadata != null) {
metadataChangeNotifier.notifyListeners();
}
} }
Future<void> locate() async { Future<void> locate() async {
@ -169,7 +171,7 @@ class ImageEntry {
addressChangeNotifier.notifyListeners(); addressChangeNotifier.notifyListeners();
} }
} catch (exception) { } catch (exception) {
debugPrint('$runtimeType addAddressToMetadata failed with exception=$exception'); debugPrint('$runtimeType addAddressToMetadata failed with path=$path coordinates=$coordinates exception=$exception');
} }
} }

View file

@ -41,17 +41,17 @@ class MetadataDb {
} }
Future<List<CatalogMetadata>> loadMetadataEntries() async { Future<List<CatalogMetadata>> loadMetadataEntries() async {
final start = DateTime.now(); // final stopwatch = Stopwatch()..start();
final db = await _database; final db = await _database;
final maps = await db.query(metadataTable); final maps = await db.query(metadataTable);
final metadataEntries = maps.map((map) => CatalogMetadata.fromMap(map)).toList(); final metadataEntries = maps.map((map) => CatalogMetadata.fromMap(map)).toList();
debugPrint('$runtimeType loadMetadataEntries complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${metadataEntries.length} entries'); // debugPrint('$runtimeType loadMetadataEntries complete in ${stopwatch.elapsed.inMilliseconds}ms with ${metadataEntries.length} entries');
return metadataEntries; return metadataEntries;
} }
Future<void> saveMetadata(Iterable<CatalogMetadata> metadataEntries) async { Future<void> saveMetadata(Iterable<CatalogMetadata> metadataEntries) async {
if (metadataEntries == null || metadataEntries.isEmpty) return; if (metadataEntries == null || metadataEntries.isEmpty) return;
final start = DateTime.now(); final stopwatch = Stopwatch()..start();
final db = await _database; final db = await _database;
final batch = db.batch(); final batch = db.batch();
metadataEntries.where((metadata) => metadata != null).forEach((metadata) => batch.insert( metadataEntries.where((metadata) => metadata != null).forEach((metadata) => batch.insert(
@ -60,7 +60,7 @@ class MetadataDb {
conflictAlgorithm: ConflictAlgorithm.replace, conflictAlgorithm: ConflictAlgorithm.replace,
)); ));
await batch.commit(noResult: true); await batch.commit(noResult: true);
debugPrint('$runtimeType saveMetadata complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${metadataEntries.length} entries'); debugPrint('$runtimeType saveMetadata complete in ${stopwatch.elapsed.inMilliseconds}ms with ${metadataEntries.length} entries');
} }
Future<void> clearAddresses() async { Future<void> clearAddresses() async {
@ -70,17 +70,17 @@ class MetadataDb {
} }
Future<List<AddressDetails>> loadAddresses() async { Future<List<AddressDetails>> loadAddresses() async {
final start = DateTime.now(); // final stopwatch = Stopwatch()..start();
final db = await _database; final db = await _database;
final maps = await db.query(addressTable); final maps = await db.query(addressTable);
final addresses = maps.map((map) => AddressDetails.fromMap(map)).toList(); final addresses = maps.map((map) => AddressDetails.fromMap(map)).toList();
debugPrint('$runtimeType loadAddresses complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${addresses.length} entries'); // debugPrint('$runtimeType loadAddresses complete in ${stopwatch.elapsed.inMilliseconds}ms with ${addresses.length} entries');
return addresses; return addresses;
} }
Future<void> saveAddresses(Iterable<AddressDetails> addresses) async { Future<void> saveAddresses(Iterable<AddressDetails> addresses) async {
if (addresses == null || addresses.isEmpty) return; if (addresses == null || addresses.isEmpty) return;
final start = DateTime.now(); final stopwatch = Stopwatch()..start();
final db = await _database; final db = await _database;
final batch = db.batch(); final batch = db.batch();
addresses.where((address) => address != null).forEach((address) => batch.insert( addresses.where((address) => address != null).forEach((address) => batch.insert(
@ -89,6 +89,6 @@ class MetadataDb {
conflictAlgorithm: ConflictAlgorithm.replace, conflictAlgorithm: ConflictAlgorithm.replace,
)); ));
await batch.commit(noResult: true); await batch.commit(noResult: true);
debugPrint('$runtimeType saveAddresses complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${addresses.length} entries'); debugPrint('$runtimeType saveAddresses complete in ${stopwatch.elapsed.inMilliseconds}ms with ${addresses.length} entries');
} }
} }

View file

@ -8,8 +8,6 @@ import 'package:flutter/services.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart'; import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
final _stopwatch = Stopwatch()..start();
class MediaStoreCollectionProvider extends StatefulWidget { class MediaStoreCollectionProvider extends StatefulWidget {
final Widget child; final Widget child;
@ -31,7 +29,7 @@ class _MediaStoreCollectionProviderState extends State<MediaStoreCollectionProvi
} }
Future<ImageCollection> _create() async { Future<ImageCollection> _create() async {
debugPrint('$runtimeType _create, elapsed=${_stopwatch.elapsed}'); final stopwatch = Stopwatch()..start();
final mediaStoreCollection = ImageCollection(entries: []); final mediaStoreCollection = ImageCollection(entries: []);
mediaStoreCollection.groupFactor = settings.collectionGroupFactor; mediaStoreCollection.groupFactor = settings.collectionGroupFactor;
mediaStoreCollection.sortFactor = settings.collectionSortFactor; mediaStoreCollection.sortFactor = settings.collectionSortFactor;
@ -49,7 +47,7 @@ class _MediaStoreCollectionProviderState extends State<MediaStoreCollectionProvi
eventChannel.receiveBroadcastStream().cast<Map>().listen( eventChannel.receiveBroadcastStream().cast<Map>().listen(
(entryMap) => mediaStoreCollection.add(ImageEntry.fromMap(entryMap)), (entryMap) => mediaStoreCollection.add(ImageEntry.fromMap(entryMap)),
onDone: () async { onDone: () async {
debugPrint('$runtimeType mediastore stream done, elapsed=${_stopwatch.elapsed}'); debugPrint('$runtimeType stream complete in ${stopwatch.elapsed.inMilliseconds}ms');
mediaStoreCollection.updateSections(); // <50ms mediaStoreCollection.updateSections(); // <50ms
// TODO reduce setup time until here // TODO reduce setup time until here
mediaStoreCollection.updateAlbums(); // <50ms mediaStoreCollection.updateAlbums(); // <50ms
@ -57,7 +55,7 @@ class _MediaStoreCollectionProviderState extends State<MediaStoreCollectionProvi
await mediaStoreCollection.catalogEntries(); // <50ms await mediaStoreCollection.catalogEntries(); // <50ms
await mediaStoreCollection.loadAddresses(); // 350ms await mediaStoreCollection.loadAddresses(); // 350ms
await mediaStoreCollection.locateEntries(); // <50ms await mediaStoreCollection.locateEntries(); // <50ms
debugPrint('$runtimeType setup end, elapsed=${_stopwatch.elapsed}'); debugPrint('$runtimeType setup end, elapsed=${stopwatch.elapsed}');
}, },
onError: (error) => debugPrint('$runtimeType mediastore stream error=$error'), onError: (error) => debugPrint('$runtimeType mediastore stream error=$error'),
); );