restored reading image bytes all at once because of streaming jank
This commit is contained in:
parent
a09e910840
commit
f7ef4c0d01
4 changed files with 69 additions and 6 deletions
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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',
|
||||||
|
|
Loading…
Reference in a new issue