restored reading image bytes all at once because of streaming jank

This commit is contained in:
Thibault Deckers 2020-06-03 12:53:42 +09:00
parent a09e910840
commit f7ef4c0d01
4 changed files with 69 additions and 6 deletions

View file

@ -108,7 +108,9 @@ public class ImageByteStreamHandler implements EventChannel.StreamHandler {
} else { } else {
try (InputStream is = cr.openInputStream(uri)) { try (InputStream is = cr.openInputStream(uri)) {
if (is != null) { if (is != null) {
streamBytes(is); // TODO TLAD streaming would allow chunk events, but in practice Flutter blocks every time we send a chunk
// streamBytes(is);
success(getBytes(is));
} else { } else {
error("getImage-image-read-null", "failed to get image from uri=" + uri, null); error("getImage-image-read-null", "failed to get image from uri=" + uri, null);
} }
@ -131,4 +133,17 @@ public class ImageByteStreamHandler implements EventChannel.StreamHandler {
success(sub); success(sub);
} }
} }
// InputStream.readAllBytes is only available from Java 9+
private byte[] getBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}
return byteBuffer.toByteArray();
}
} }

View file

@ -14,6 +14,11 @@ allprojects {
google() google()
jcenter() jcenter()
} }
// gradle.projectsEvaluated {
// tasks.withType(JavaCompile) {
// options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
// }
// }
} }
rootProject.buildDir = '../build' rootProject.buildDir = '../build'

View file

@ -1,5 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
@ -40,15 +40,18 @@ class ImageFileService {
static Future<Uint8List> getImage(String uri, String mimeType) { static Future<Uint8List> getImage(String uri, String mimeType) {
try { try {
final completer = Completer<Uint8List>(); final completer = Completer<Uint8List>.sync();
final bytesBuilder = BytesBuilder(copy: false); final sink = _OutputBuffer();
byteChannel.receiveBroadcastStream(<String, dynamic>{ byteChannel.receiveBroadcastStream(<String, dynamic>{
'uri': uri, 'uri': uri,
'mimeType': mimeType, 'mimeType': mimeType,
}).listen( }).listen(
(data) => bytesBuilder.add(data as Uint8List), (chunk) => sink.add(chunk as Uint8List),
onError: completer.completeError, onError: completer.completeError,
onDone: () => completer.complete(bytesBuilder.takeBytes()), onDone: () {
sink.close();
completer.complete(sink.bytes);
},
cancelOnError: true, cancelOnError: true,
); );
return completer.future; return completer.future;
@ -193,3 +196,37 @@ class MoveOpEvent extends ImageOpEvent {
return 'MoveOpEvent{success=$success, uri=$uri, newFields=$newFields}'; return 'MoveOpEvent{success=$success, uri=$uri, newFields=$newFields}';
} }
} }
// copied from `consolidateHttpClientResponseBytes` in flutter/foundation
class _OutputBuffer extends ByteConversionSinkBase {
List<List<int>> _chunks = <List<int>>[];
int _contentLength = 0;
Uint8List _bytes;
@override
void add(List<int> chunk) {
assert(_bytes == null);
_chunks.add(chunk);
_contentLength += chunk.length;
}
@override
void close() {
if (_bytes != null) {
// We've already been closed; this is a no-op
return;
}
_bytes = Uint8List(_contentLength);
int offset = 0;
for (final List<int> chunk in _chunks) {
_bytes.setRange(offset, offset + chunk.length, chunk);
offset += chunk.length;
}
_chunks = null;
}
Uint8List get bytes {
assert(_bytes != null);
return _bytes;
}
}

View file

@ -29,6 +29,12 @@ class Constants {
static const svgColorFilter = ColorFilter.mode(svgBackground, BlendMode.dstOver); static const svgColorFilter = ColorFilter.mode(svgBackground, BlendMode.dstOver);
static const List<Dependency> androidDependencies = [ static const List<Dependency> androidDependencies = [
Dependency(
name: 'CWAC-Document',
license: 'Apache 2.0',
licenseUrl: 'https://github.com/commonsguy/cwac-document/blob/master/LICENSE',
sourceUrl: 'https://github.com/commonsguy/cwac-document',
),
Dependency( Dependency(
name: 'Glide', name: 'Glide',
license: 'Apache 2.0, BSD 2-Clause', license: 'Apache 2.0, BSD 2-Clause',