为文件传输分配新字节 [] 时如何防止内存不足错误?
How do I prevent OutOfMemory Error when allocating new byte[] for File transfer?
我正在尝试读取文件以便通过 Wear App 发送它,但我遇到了 OutOfMemory 异常。
File file = new File(filePath);
final FileInputStream fileInputStream = new FileInputStream(file);
byte fileContent[] = new byte[(int) file.length()]; //***BOMBS HERE***
fileInputStream.read(fileContent);
fileInputStream.close();
Asset programDataAsset = Asset.createFromBytes(fileContent);
异常说明如下:
java.lang.OutOfMemoryError: Failed to allocate a 31150467 byte allocation with 2097152 free bytes and 16MB until OOM
at com.rithmio.coach.wear.TransferService.sendAssetToMobile(TransferService.java:110)
at com.rithmio.coach.wear.TransferService.onHandleIntent(TransferService.java:84)
at com.rithmio.coach.wear.TransferService.run(TransferService.java:60)
at java.lang.Thread.run(Thread.java:818)
您应该使用缓冲区而不是尝试将整个文件存储为数组。将部分文件读入字节数组,然后将它们写出到流中。这也将防止内存较少的设备出现 OOM 错误。
int fileLength = (int) file.length();
while(fileLength > 0){
byte[] arr;
if(fileLength > 1024){
arr = new byte[1024];
}else{
arr = new byte[fileLength];
fileInputStream.read(arr);
// write to outputStream/file transfer
fileLength -= arr.length;
}
让我们使用 ChannelApi. We also do not have to worry about chunks like I said in my comment. Google thought ahead and made a convenience method for sending files. public abstract PendingResult sendFile (GoogleApiClient client, Uri uri)
来解决这个问题
private String pickBestNodeId(List<Node> nodes) {
String bestNodeId = null;
// Find a nearby node or pick one arbitrarily
for (Node node : nodes) {
if (node.isNearby()) {
return node.getId();
}
bestNodeId = node.getId();
}
return bestNodeId;
}
public boolean send(File f) {
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
// Request access only to the Wearable API
.addApi(Wearable.API)
.build();
mGoogleApiClient.blockingConnect();
Channel channel = openChannel(mGoogleApiClient, pickBestNodeId(Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await()), "/your/arbitrary/application/specific/path/").await(); //NOTE THE PATH IS ARBITRARY, IT CAN BE WHATEVER YOU WANT. IT DOES NOT POINT TO ANYTHING, AND CAN EVEN BE LEFT WITH WHAT I HAVE.
boolean didSend = channel.sendFile(mGoogleApiClient, f.toURI()).await().isSuccess();
channel.close(mGoogleApiClient);
mGoogleApiClient.disconnect();
return didSend;
}
注意: 这使用了阻塞方法,不应在 ui 线程中 运行。
如果你希望调用是非阻塞的,你应该省略我对 PendingResult.await()
的用法,并设置 PendingResult
的结果回调。可以通过 setResultCallback(ResultCallback callback).
设置回调
我建议您使用 ByteArrayOutputStream
。然后从 InputStream
中读取,使用此代码:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
int b;
while((b = input_stream.read()) != -1) {
stream.write(b);
}
然后,您可以使用 for(byte b : stream.toByteArray()) {...}
遍历字节
我正在尝试读取文件以便通过 Wear App 发送它,但我遇到了 OutOfMemory 异常。
File file = new File(filePath);
final FileInputStream fileInputStream = new FileInputStream(file);
byte fileContent[] = new byte[(int) file.length()]; //***BOMBS HERE***
fileInputStream.read(fileContent);
fileInputStream.close();
Asset programDataAsset = Asset.createFromBytes(fileContent);
异常说明如下:
java.lang.OutOfMemoryError: Failed to allocate a 31150467 byte allocation with 2097152 free bytes and 16MB until OOM
at com.rithmio.coach.wear.TransferService.sendAssetToMobile(TransferService.java:110)
at com.rithmio.coach.wear.TransferService.onHandleIntent(TransferService.java:84)
at com.rithmio.coach.wear.TransferService.run(TransferService.java:60)
at java.lang.Thread.run(Thread.java:818)
您应该使用缓冲区而不是尝试将整个文件存储为数组。将部分文件读入字节数组,然后将它们写出到流中。这也将防止内存较少的设备出现 OOM 错误。
int fileLength = (int) file.length();
while(fileLength > 0){
byte[] arr;
if(fileLength > 1024){
arr = new byte[1024];
}else{
arr = new byte[fileLength];
fileInputStream.read(arr);
// write to outputStream/file transfer
fileLength -= arr.length;
}
让我们使用 ChannelApi. We also do not have to worry about chunks like I said in my comment. Google thought ahead and made a convenience method for sending files. public abstract PendingResult sendFile (GoogleApiClient client, Uri uri)
来解决这个问题private String pickBestNodeId(List<Node> nodes) {
String bestNodeId = null;
// Find a nearby node or pick one arbitrarily
for (Node node : nodes) {
if (node.isNearby()) {
return node.getId();
}
bestNodeId = node.getId();
}
return bestNodeId;
}
public boolean send(File f) {
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
// Request access only to the Wearable API
.addApi(Wearable.API)
.build();
mGoogleApiClient.blockingConnect();
Channel channel = openChannel(mGoogleApiClient, pickBestNodeId(Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await()), "/your/arbitrary/application/specific/path/").await(); //NOTE THE PATH IS ARBITRARY, IT CAN BE WHATEVER YOU WANT. IT DOES NOT POINT TO ANYTHING, AND CAN EVEN BE LEFT WITH WHAT I HAVE.
boolean didSend = channel.sendFile(mGoogleApiClient, f.toURI()).await().isSuccess();
channel.close(mGoogleApiClient);
mGoogleApiClient.disconnect();
return didSend;
}
注意: 这使用了阻塞方法,不应在 ui 线程中 运行。
如果你希望调用是非阻塞的,你应该省略我对 PendingResult.await()
的用法,并设置 PendingResult
的结果回调。可以通过 setResultCallback(ResultCallback callback).
我建议您使用 ByteArrayOutputStream
。然后从 InputStream
中读取,使用此代码:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
int b;
while((b = input_stream.read()) != -1) {
stream.write(b);
}
然后,您可以使用 for(byte b : stream.toByteArray()) {...}