上一篇文章我们最终走到了键盘监听即processTerminalInput回调里
监听
然后在_commonTerminalInputHandler
我们可以看到对各种键盘事件的回调,我们找到r与R
case 'r':
if (!residentRunner.canHotReload) {
return false;
}
final OperationResult result = await residentRunner.restart(fullRestart: false);
if (result.fatal) {
throwToolExit(result.message);
}
if (!result.isOk) {
globals.printStatus('Try again after fixing the above error(s).', emphasis: true);
}
return true;
case 'R':
// If hot restart is not supported for all devices, ignore the command.
if (!residentRunner.canHotRestart || !residentRunner.hotMode) {
return false;
}
final OperationResult result = await residentRunner.restart(fullRestart: true);
if (result.fatal) {
throwToolExit(result.message);
}
if (!result.isOk) {
globals.printStatus('Try again after fixing the above error(s).', emphasis: true);
}
return true;
我们在键盘输入r,断点实际上会走到run_hot.dart的restart方法中
@override
Future<OperationResult> restart({
bool fullRestart = false,
String reason,
bool benchmarkMode = false,
bool silent = false,
bool pause = false,
}) async {
String targetPlatform;
String sdkName;
bool emulator;
if (flutterDevices.length == 1) {
final Device device = flutterDevices.first.device;
targetPlatform = getNameForTargetPlatform(await device.targetPlatform);
sdkName = await device.sdkNameAndVersion;
emulator = await device.isLocalEmulator;
} else if (flutterDevices.length > 1) {
targetPlatform = 'multiple';
sdkName = 'multiple';
emulator = false;
} else {
targetPlatform = 'unknown';
sdkName = 'unknown';
emulator = false;
}
final Stopwatch timer = Stopwatch()..start();
if (fullRestart) {
final OperationResult result = await _fullRestartHelper(
targetPlatform: targetPlatform,
sdkName: sdkName,
emulator: emulator,
reason: reason,
benchmarkMode: benchmarkMode,
silent: silent,
);
if (!silent) {
globals.printStatus('Restarted application in ${getElapsedAsMilliseconds(timer.elapsed)}.');
}
return result;
}
final OperationResult result = await _hotReloadHelper(
targetPlatform: targetPlatform,
sdkName: sdkName,
emulator: emulator,
reason: reason,
pause: pause,
);
if (result.isOk) {
final String elapsed = getElapsedAsMilliseconds(timer.elapsed);
if (!silent) {
globals.printStatus('${result.message} in $elapsed.');
}
}
return result;
}
断点走入_hotReloadHelper中
Future<OperationResult> _hotReloadHelper({
String targetPlatform,
String sdkName,
bool emulator,
String reason,
bool pause,
}) async {
Status status = globals.logger.startProgress(
'Performing hot reload...',
timeout: timeoutConfiguration.fastOperation,
progressId: 'hot.reload',
);
OperationResult result;
try {
result = await _reloadSources(
targetPlatform: targetPlatform,
sdkName: sdkName,
emulator: emulator,
reason: reason,
pause: pause,
onSlow: (String message) {
status?.cancel();
status = globals.logger.startProgress(
message,
timeout: timeoutConfiguration.slowOperation,
progressId: 'hot.reload',
);
},
);
} on rpc.RpcException {
HotEvent('exception',
targetPlatform: targetPlatform,
sdkName: sdkName,
emulator: emulator,
fullRestart: false,
reason: reason).send();
return OperationResult(1, 'hot reload failed to complete', fatal: true);
} finally {
status.cancel();
}
return result;
}
核心代码_reloadSources,继续往下跟
Future<OperationResult> _reloadSources({
String targetPlatform,
String sdkName,
bool emulator,
bool pause = false,
String reason,
void Function(String message) onSlow,
}) async {
for (final FlutterDevice device in flutterDevices) {
for (final FlutterView view in device.views) {
if (view.uiIsolate == null) {
return OperationResult(2, 'Application isolate not found', fatal: true);
}
}
}
final Stopwatch reloadTimer = Stopwatch()..start();
if (!_isPaused()) {
globals.printTrace('Refreshing active FlutterViews before reloading.');
await refreshViews();
}
final Stopwatch devFSTimer = Stopwatch()..start();
final UpdateFSReport updatedDevFS = await _updateDevFS();
核心代码_updateDevFS,继续往下走核心代码UpdateFSReport
final UpdateFSReport results = UpdateFSReport(success: true);
for (final FlutterDevice device in flutterDevices) {
results.incorporateResults(await device.updateDevFS(
mainPath: mainPath,
target: target,
bundle: assetBundle,
firstBuildTime: firstBuildTime,
bundleFirstUpload: isFirstUpload,
bundleDirty: !isFirstUpload && rebuildBundle,
fullRestart: fullRestart,
projectRootPath: projectRootPath,
pathToReload: getReloadPath(fullRestart: fullRestart),
invalidatedFiles: invalidatedFiles,
dillOutputPath: dillOutputPath,
));
}
return results;
我看到了mainPath
mainPath
这个mainPath就是我们加载的那个工程代码地址
进入 device.updateDevFS
Future<UpdateFSReport> updateDevFS({
String mainPath,
String target,
AssetBundle bundle,
DateTime firstBuildTime,
bool bundleFirstUpload = false,
bool bundleDirty = false,
bool fullRestart = false,
String projectRootPath,
String pathToReload,
@required String dillOutputPath,
@required List<Uri> invalidatedFiles,
}) async {
final Status devFSStatus = globals.logger.startProgress(
'Syncing files to device ${device.name}...',
timeout: timeoutConfiguration.fastOperation,
);
UpdateFSReport report;
try {
report = await devFS.update(
mainPath: mainPath,
target: target,
bundle: bundle,
firstBuildTime: firstBuildTime,
bundleFirstUpload: bundleFirstUpload,
generator: generator,
fullRestart: fullRestart,
dillOutputPath: dillOutputPath,
trackWidgetCreation: buildInfo.trackWidgetCreation,
projectRootPath: projectRootPath,
pathToReload: pathToReload,
invalidatedFiles: invalidatedFiles,
);
} on DevFSException {
devFSStatus.cancel();
return UpdateFSReport(success: false);
}
devFSStatus.stop();
globals.printTrace('Synced ${getSizeAsMB(report.syncedBytes)}.');
return report;
}
继续进入devFS.update
if (!bundleFirstUpload) {
final String compiledBinary = compilerOutput?.outputFilename;
if (compiledBinary != null && compiledBinary.isNotEmpty) {
final Uri entryUri = globals.fs.path.toUri(projectRootPath != null
? globals.fs.path.relative(pathToReload, from: projectRootPath)
: pathToReload,
);
final DevFSFileContent content = DevFSFileContent(globals.fs.file(compiledBinary));
syncedBytes += content.size;
dirtyEntries[entryUri] = content;
}
}
复制content路径
content
打开文件地址
文件地址
打开终端,cd到该文件夹下,然后strings app.dill.incremental.dill
终端
就可以打印出了增量文件了
增量文件
我们顺着代码继续往下看
if (dirtyEntries.isNotEmpty) {
try {
await _httpWriter.write(dirtyEntries);
} on SocketException catch (socketException, stackTrace) {
globals.printTrace('DevFS sync failed. Lost connection to device: $socketException');
throw DevFSException('Lost connection to device.', socketException, stackTrace);
} on Exception catch (exception, stackTrace) {
globals.printError('Could not update files on device: $exception');
throw DevFSException('Sync failed', exception, stackTrace);
}
}
我们可以看到_httpWriter,这个_httpWriter是什么呢?
_httpWriter
这个httpWriter就是我们的dartVM,发送网络请求的过程
进入write方法
Future<void> write(Map<Uri, DevFSContent> entries) async {
_client.maxConnectionsPerHost = kMaxInFlight;
_completer = Completer<void>();
_outstanding = Map<Uri, DevFSContent>.from(entries);
_scheduleWrites();
await _completer.future;
}
进入_scheduleWrites
void _scheduleWrites() {
while ((_inFlight < kMaxInFlight) && (!_completer.isCompleted) && _outstanding.isNotEmpty) {
final Uri deviceUri = _outstanding.keys.first;
final DevFSContent content = _outstanding.remove(deviceUri);
_startWrite(deviceUri, content, retry: 10);
_inFlight += 1;
}
if ((_inFlight == 0) && (!_completer.isCompleted) && _outstanding.isEmpty) {
_completer.complete();
}
}
核心是_startWrite方法
Future<void> _startWrite(
Uri deviceUri,
DevFSContent content, {
int retry = 0,
}) async {
while(true) {
try {
final HttpClientRequest request = await _client.putUrl(httpAddress);
request.headers.removeAll(HttpHeaders.acceptEncodingHeader);
request.headers.add('dev_fs_name', fsName);
request.headers.add('dev_fs_uri_b64', base64.encode(utf8.encode('$deviceUri')));
final Stream<List<int>> contents = content.contentsAsCompressedStream();
await request.addStream(contents);
final HttpClientResponse response = await request.close();
response.listen((_) => null,
onError: (dynamic error) { globals.printTrace('error: $error'); },
cancelOnError: true);
break;
} catch (error, trace) { // ignore: avoid_catches_without_on_clauses
// We treat OSError as an Exception.
// See: https://github.com/dart-lang/sdk/issues/40934
if (error is! Exception && error is! OSError) {
rethrow;
}
if (!_completer.isCompleted) {
globals.printTrace('Error writing "$deviceUri" to DevFS: $error');
if (retry > 0) {
retry--;
globals.printTrace('trying again in a few - $retry more attempts left');
await Future<void>.delayed(const Duration(milliseconds: 500));
continue;
}
_completer.completeError(error, trace);
}
}
}
_inFlight -= 1;
_scheduleWrites();
}
我们可以很明显的看到HttpClientRequest发起了一个http请求
网友评论