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 {
try (InputStream is = cr.openInputStream(uri)) {
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 {
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);
}
}
// 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()
jcenter()
}
// gradle.projectsEvaluated {
// tasks.withType(JavaCompile) {
// options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
// }
// }
}
rootProject.buildDir = '../build'

View file

@ -1,5 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'dart:typed_data';
import 'package:aves/model/image_entry.dart';
@ -40,15 +40,18 @@ class ImageFileService {
static Future<Uint8List> getImage(String uri, String mimeType) {
try {
final completer = Completer<Uint8List>();
final bytesBuilder = BytesBuilder(copy: false);
final completer = Completer<Uint8List>.sync();
final sink = _OutputBuffer();
byteChannel.receiveBroadcastStream(<String, dynamic>{
'uri': uri,
'mimeType': mimeType,
}).listen(
(data) => bytesBuilder.add(data as Uint8List),
(chunk) => sink.add(chunk as Uint8List),
onError: completer.completeError,
onDone: () => completer.complete(bytesBuilder.takeBytes()),
onDone: () {
sink.close();
completer.complete(sink.bytes);
},
cancelOnError: true,
);
return completer.future;
@ -193,3 +196,37 @@ class MoveOpEvent extends ImageOpEvent {
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 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(
name: 'Glide',
license: 'Apache 2.0, BSD 2-Clause',