Commit b11b2a1d authored by John McCutchan's avatar John McCutchan Committed by GitHub

Add loader screen for --hot mode (#5113)

parent 578d98ea
This directory contains a small Flutter application that is run while
an application is being copied onto the device.
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: 'Flutter Initial Load',
home: new Scaffold(
body: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('Loading application onto device...',
style: new TextStyle(fontSize: 24.0)),
new CircularProgressIndicator(value: null)
]
)
)
)
);
}
...@@ -37,6 +37,7 @@ class AssetBundleEntry { ...@@ -37,6 +37,7 @@ class AssetBundleEntry {
} }
bool get isStringEntry => _contents != null; bool get isStringEntry => _contents != null;
int get contentsLength => _contents.length;
final File file; final File file;
final String _contents; final String _contents;
......
...@@ -49,6 +49,17 @@ class DevFSEntry { ...@@ -49,6 +49,17 @@ class DevFSEntry {
return _fileStat.modified.isAfter(_oldFileStat.modified); return _fileStat.modified.isAfter(_oldFileStat.modified);
} }
int get size {
if (_isSourceEntry) {
return bundleEntry.contentsLength;
} else {
if (_fileStat == null) {
_stat();
}
return _fileStat.size;
}
}
void _stat() { void _stat() {
if (_isSourceEntry) if (_isSourceEntry)
return; return;
...@@ -151,6 +162,8 @@ class DevFS { ...@@ -151,6 +162,8 @@ class DevFS {
final Directory rootDirectory; final Directory rootDirectory;
final Map<String, DevFSEntry> _entries = <String, DevFSEntry>{}; final Map<String, DevFSEntry> _entries = <String, DevFSEntry>{};
final List<Future<Response>> _pendingWrites = new List<Future<Response>>(); final List<Future<Response>> _pendingWrites = new List<Future<Response>>();
int _bytes = 0;
int get bytes => _bytes;
Uri _baseUri; Uri _baseUri;
Uri get baseUri => _baseUri; Uri get baseUri => _baseUri;
...@@ -166,6 +179,7 @@ class DevFS { ...@@ -166,6 +179,7 @@ class DevFS {
} }
Future<dynamic> update([AssetBundle bundle = null]) async { Future<dynamic> update([AssetBundle bundle = null]) async {
_bytes = 0;
// Mark all entries as not seen. // Mark all entries as not seen.
_entries.forEach((String path, DevFSEntry entry) { _entries.forEach((String path, DevFSEntry entry) {
entry._wasSeen = false; entry._wasSeen = false;
...@@ -244,6 +258,7 @@ class DevFS { ...@@ -244,6 +258,7 @@ class DevFS {
entry._wasSeen = true; entry._wasSeen = true;
bool needsWrite = entry.isModified; bool needsWrite = entry.isModified;
if (needsWrite) { if (needsWrite) {
_bytes += entry.size;
Future<dynamic> pendingWrite = _operations.writeFile(fsName, entry); Future<dynamic> pendingWrite = _operations.writeFile(fsName, entry);
if (pendingWrite != null) { if (pendingWrite != null) {
_pendingWrites.add(pendingWrite); _pendingWrites.add(pendingWrite);
...@@ -261,6 +276,9 @@ class DevFS { ...@@ -261,6 +276,9 @@ class DevFS {
_entries[devicePath] = entry; _entries[devicePath] = entry;
} }
entry._wasSeen = true; entry._wasSeen = true;
bool needsWrite = entry.isModified;
if (needsWrite) {
_bytes += entry.size;
Future<dynamic> pendingWrite = _operations.writeFile(fsName, entry); Future<dynamic> pendingWrite = _operations.writeFile(fsName, entry);
if (pendingWrite != null) { if (pendingWrite != null) {
_pendingWrites.add(pendingWrite); _pendingWrites.add(pendingWrite);
...@@ -268,6 +286,7 @@ class DevFS { ...@@ -268,6 +286,7 @@ class DevFS {
printTrace('DevFS: Failed to sync "$devicePath"'); printTrace('DevFS: Failed to sync "$devicePath"');
} }
} }
}
bool _shouldIgnore(String devicePath) { bool _shouldIgnore(String devicePath) {
List<String> ignoredPrefixes = <String>['android/', List<String> ignoredPrefixes = <String>['android/',
......
...@@ -11,6 +11,7 @@ import 'application_package.dart'; ...@@ -11,6 +11,7 @@ import 'application_package.dart';
import 'base/logger.dart'; import 'base/logger.dart';
import 'base/utils.dart'; import 'base/utils.dart';
import 'build_info.dart'; import 'build_info.dart';
import 'cache.dart';
import 'commands/build_apk.dart'; import 'commands/build_apk.dart';
import 'commands/install.dart'; import 'commands/install.dart';
import 'commands/trace.dart'; import 'commands/trace.dart';
...@@ -31,6 +32,15 @@ String findMainDartFile([String target]) { ...@@ -31,6 +32,15 @@ String findMainDartFile([String target]) {
return targetPath; return targetPath;
} }
String getDevFSLoaderScript() {
return path.absolute(path.join(Cache.flutterRoot,
'packages',
'flutter',
'bin',
'loader',
'loader_app.dart'));
}
class RunAndStayResident { class RunAndStayResident {
RunAndStayResident( RunAndStayResident(
this.device, { this.device, {
...@@ -176,8 +186,10 @@ class RunAndStayResident { ...@@ -176,8 +186,10 @@ class RunAndStayResident {
if (traceStartup != null) if (traceStartup != null)
platformArgs = <String, dynamic>{ 'trace-startup': traceStartup }; platformArgs = <String, dynamic>{ 'trace-startup': traceStartup };
if (!hotMode || (hotMode && !device.needsDevFS))
printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...'); printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...');
_loggingSubscription = device.logReader.logLines.listen((String line) { _loggingSubscription = device.logReader.logLines.listen((String line) {
if (!line.contains('Observatory listening on http') && !line.contains('Diagnostic server listening on http')) if (!line.contains('Observatory listening on http') && !line.contains('Diagnostic server listening on http'))
printStatus(line); printStatus(line);
...@@ -186,7 +198,7 @@ class RunAndStayResident { ...@@ -186,7 +198,7 @@ class RunAndStayResident {
_result = await device.startApp( _result = await device.startApp(
_package, _package,
debuggingOptions.buildMode, debuggingOptions.buildMode,
mainPath: _mainPath, mainPath: (hotMode && device.needsDevFS) ? getDevFSLoaderScript() : _mainPath,
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,
platformArgs: platformArgs, platformArgs: platformArgs,
route: route route: route
...@@ -213,7 +225,7 @@ class RunAndStayResident { ...@@ -213,7 +225,7 @@ class RunAndStayResident {
printError('Could not perform initial file synchronization.'); printError('Could not perform initial file synchronization.');
return 3; return 3;
} }
printStatus('Launching from sources.'); printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...');
await _launchFromDevFS(_package, _mainPath); await _launchFromDevFS(_package, _mainPath);
} }
observatory.populateIsolateInfo(); observatory.populateIsolateInfo();
...@@ -345,9 +357,10 @@ class RunAndStayResident { ...@@ -345,9 +357,10 @@ class RunAndStayResident {
}); });
} }
Status devFSStatus = logger.startProgress('Updating files on device...'); Status devFSStatus = logger.startProgress('Syncing files on device...');
await _devFS.update(); await _devFS.update();
devFSStatus.stop(showElapsedTime: true); devFSStatus.stop(showElapsedTime: true);
printStatus('Synced ${getSizeAsMB(_devFS.bytes)} MB');
return true; return true;
} }
...@@ -388,7 +401,13 @@ class RunAndStayResident { ...@@ -388,7 +401,13 @@ class RunAndStayResident {
reloadStatus.stop(showElapsedTime: true); reloadStatus.stop(showElapsedTime: true);
Status reassembleStatus = Status reassembleStatus =
logger.startProgress('Reassembling application'); logger.startProgress('Reassembling application');
try {
await observatory.flutterReassemble(observatory.firstIsolateId); await observatory.flutterReassemble(observatory.firstIsolateId);
} catch (_) {
reassembleStatus.stop(showElapsedTime: true);
printError('Reassembling application failed.');
return false;
}
reassembleStatus.stop(showElapsedTime: true); reassembleStatus.stop(showElapsedTime: true);
return true; return true;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment