Skip to content

Commit e60f35a

Browse files
committed
Add file stream api
1 parent a2a1fd0 commit e60f35a

File tree

3 files changed

+264
-54
lines changed

3 files changed

+264
-54
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2015-present, Parse, LLC.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
package com.parse;
10+
11+
import java.io.InputStream;
12+
13+
/**
14+
* A {@code GetDataStreamCallback} is used to run code after a {@link ParseFile} fetches its data on
15+
* a background thread.
16+
* <p/>
17+
* The easiest way to use a {@code GetDataStreamCallback} is through an anonymous inner class.
18+
* Override the {@code done} function to specify what the callback should do after the fetch is
19+
* complete. The {@code done} function will be run in the UI thread, while the fetch happens in a
20+
* background thread. This ensures that the UI does not freeze while the fetch happens.
21+
* <p/>
22+
* <pre>
23+
* file.getDataStreamInBackground(new GetDataStreamCallback() {
24+
* public void done(InputSteam input, ParseException e) {
25+
* // ...
26+
* }
27+
* });
28+
* </pre>
29+
*/
30+
public interface GetDataStreamCallback extends ParseCallback2<InputStream, ParseException> {
31+
/**
32+
* Override this function with the code you want to run after the fetch is complete.
33+
*
34+
* @param input
35+
* The data that was retrieved, or {@code null} if it did not succeed.
36+
* @param e
37+
* The exception raised by the fetch, or {@code null} if it succeeded.
38+
*/
39+
@Override
40+
public void done(InputStream input, ParseException e);
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2015-present, Parse, LLC.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
package com.parse;
10+
11+
import java.io.File;
12+
13+
/**
14+
* A {@code GetFileCallback} is used to run code after a {@link ParseFile} fetches its data on
15+
* a background thread.
16+
* <p/>
17+
* The easiest way to use a {@code GetFileCallback} is through an anonymous inner class.
18+
* Override the {@code done} function to specify what the callback should do after the fetch is
19+
* complete. The {@code done} function will be run in the UI thread, while the fetch happens in a
20+
* background thread. This ensures that the UI does not freeze while the fetch happens.
21+
* <p/>
22+
* <pre>
23+
* file.getFileInBackground(new GetFileCallback() {
24+
* public void done(File file, ParseException e) {
25+
* // ...
26+
* }
27+
* });
28+
* </pre>
29+
*/
30+
public interface GetFileCallback extends ParseCallback2<File, ParseException> {
31+
/**
32+
* Override this function with the code you want to run after the fetch is complete.
33+
*
34+
* @param file
35+
* The data that was retrieved, or {@code null} if it did not succeed.
36+
* @param e
37+
* The exception raised by the fetch, or {@code null} if it succeeded.
38+
*/
39+
@Override
40+
public void done(File file, ParseException e);
41+
}

Parse/src/main/java/com/parse/ParseFile.java

Lines changed: 182 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
import org.json.JSONObject;
1313

1414
import java.io.File;
15+
import java.io.FileInputStream;
1516
import java.io.IOException;
17+
import java.io.InputStream;
1618
import java.util.Collections;
1719
import java.util.HashSet;
1820
import java.util.Set;
@@ -362,60 +364,14 @@ public void saveInBackground(SaveCallback callback) {
362364

363365
/**
364366
* Synchronously gets the data for this object. You probably want to use
365-
* {@link #getDataInBackground} instead unless you're already in a background thread.
367+
* {@link #getDataInBackground()} instead unless you're already in a background thread.
366368
*/
367369
public byte[] getData() throws ParseException {
368370
return ParseTaskUtils.wait(getDataInBackground());
369371
}
370372

371-
private Task<byte[]> getDataAsync(final ProgressCallback progressCallback, Task<Void> toAwait,
372-
final Task<Void> cancellationToken) {
373-
// If data is already available, just return immediately.
374-
if (data != null) {
375-
// in-memory
376-
return Task.forResult(data);
377-
}
378-
if (cancellationToken != null && cancellationToken.isCancelled()) {
379-
return Task.cancelled();
380-
}
381-
382-
// Wait for our turn in the queue, and return immediately if data is now available.
383-
return toAwait.continueWithTask(new Continuation<Void, Task<byte[]>>() {
384-
@Override
385-
public Task<byte[]> then(Task<Void> task) throws Exception {
386-
// If data is already available, just return immediately.
387-
if (data != null) {
388-
// in-memory
389-
return Task.forResult(data);
390-
}
391-
if (cancellationToken != null && cancellationToken.isCancelled()) {
392-
return Task.cancelled();
393-
}
394-
395-
return getFileController().fetchAsync(
396-
state,
397-
null,
398-
progressCallbackOnMainThread(progressCallback),
399-
cancellationToken).onSuccess(new Continuation<File, byte[]>() {
400-
@Override
401-
public byte[] then(Task<File> task) throws Exception {
402-
File file = task.getResult();
403-
try {
404-
data = ParseFileUtils.readFileToByteArray(file);
405-
return data;
406-
} catch (IOException e) {
407-
// do nothing
408-
}
409-
return null;
410-
}
411-
});
412-
}
413-
});
414-
}
415-
416373
/**
417-
* Gets the data for this object in a background thread. `progressCallback` is guaranteed to be
418-
* called with 100 before dataCallback is called.
374+
* Gets the data for this object in a background thread.
419375
*
420376
* @param progressCallback
421377
* A ProgressCallback that is called periodically with progress updates.
@@ -428,7 +384,19 @@ public Task<byte[]> getDataInBackground(final ProgressCallback progressCallback)
428384
return taskQueue.enqueue(new Continuation<Void, Task<byte[]>>() {
429385
@Override
430386
public Task<byte[]> then(Task<Void> toAwait) throws Exception {
431-
return getDataAsync(progressCallback, toAwait, cts.getTask());
387+
return fetchInBackground(progressCallback, toAwait, cts.getTask()).onSuccess(new Continuation<File, byte[]>() {
388+
@Override
389+
public byte[] then(Task<File> task) throws Exception {
390+
File file = task.getResult();
391+
try {
392+
data = ParseFileUtils.readFileToByteArray(file);
393+
return data;
394+
} catch (IOException e) {
395+
// do nothing
396+
}
397+
return null;
398+
}
399+
});
432400
}
433401
}).continueWithTask(new Continuation<byte[], Task<byte[]>>() {
434402
@Override
@@ -441,8 +409,7 @@ public Task<byte[]> then(Task<byte[]> task) throws Exception {
441409
}
442410

443411
/**
444-
* Gets the data for this object in a background thread. `progressCallback` is guaranteed to be
445-
* called with 100 before dataCallback is called.
412+
* Gets the data for this object in a background thread.
446413
*
447414
* @return A Task that is resolved when the data has been fetched.
448415
*/
@@ -451,8 +418,7 @@ public Task<byte[]> getDataInBackground() {
451418
}
452419

453420
/**
454-
* Gets the data for this object in a background thread. `progressCallback` is guaranteed to be
455-
* called with 100 before dataCallback is called.
421+
* Gets the data for this object in a background thread.
456422
*
457423
* @param dataCallback
458424
* A GetDataCallback that is called when the get completes.
@@ -474,6 +440,169 @@ public void getDataInBackground(GetDataCallback dataCallback) {
474440
ParseTaskUtils.callbackOnMainThreadAsync(getDataInBackground(), dataCallback);
475441
}
476442

443+
/**
444+
* Synchronously gets the file pointer for this object. You probably want to use
445+
* {@link #getFileInBackground()} instead unless you're already in a background thread.
446+
*/
447+
public File getFile() throws ParseException {
448+
return ParseTaskUtils.wait(getFileInBackground());
449+
}
450+
451+
/**
452+
* Gets the file pointer for this object in a background thread.
453+
*
454+
* @param progressCallback
455+
* A ProgressCallback that is called periodically with progress updates.
456+
* @return A Task that is resolved when the file pointer of this object has been fetched.
457+
*/
458+
public Task<File> getFileInBackground(final ProgressCallback progressCallback) {
459+
final Task<Void>.TaskCompletionSource cts = Task.create();
460+
currentTasks.add(cts);
461+
462+
return taskQueue.enqueue(new Continuation<Void, Task<File>>() {
463+
@Override
464+
public Task<File> then(Task<Void> toAwait) throws Exception {
465+
return fetchInBackground(progressCallback, toAwait, cts.getTask());
466+
}
467+
}).continueWithTask(new Continuation<File, Task<File>>() {
468+
@Override
469+
public Task<File> then(Task<File> task) throws Exception {
470+
cts.trySetResult(null); // release
471+
currentTasks.remove(cts);
472+
return task;
473+
}
474+
});
475+
}
476+
477+
/**
478+
* Gets the file pointer for this object in a background thread.
479+
*
480+
* @return A Task that is resolved when the data has been fetched.
481+
*/
482+
public Task<File> getFileInBackground() {
483+
return getFileInBackground((ProgressCallback)null);
484+
}
485+
486+
/**
487+
* Gets the file pointer for this object in a background thread. `progressCallback` is guaranteed
488+
* to be called with 100 before `fileCallback` is called.
489+
*
490+
* @param fileCallback
491+
* A GetFileCallback that is called when the get completes.
492+
* @param progressCallback
493+
* A ProgressCallback that is called periodically with progress updates.
494+
*/
495+
public void getFileInBackground(GetFileCallback fileCallback,
496+
final ProgressCallback progressCallback) {
497+
ParseTaskUtils.callbackOnMainThreadAsync(getFileInBackground(progressCallback), fileCallback);
498+
}
499+
500+
/**
501+
* Gets the file pointer for this object in a background thread.
502+
*
503+
* @param fileCallback
504+
* A GetFileCallback that is called when the get completes.
505+
*/
506+
public void getFileInBackground(GetFileCallback fileCallback) {
507+
ParseTaskUtils.callbackOnMainThreadAsync(getFileInBackground(), fileCallback);
508+
}
509+
510+
/**
511+
* Synchronously gets the data stream for this object. You probably want to use
512+
* {@link #getDataStreamInBackground} instead unless you're already in a background thread.
513+
*/
514+
public InputStream getDataStream() throws ParseException {
515+
return ParseTaskUtils.wait(getDataStreamInBackground());
516+
}
517+
518+
/**
519+
* Gets the data stream for this object in a background thread.
520+
*
521+
* @param progressCallback
522+
* A ProgressCallback that is called periodically with progress updates.
523+
* @return A Task that is resolved when the data stream of this object has been fetched.
524+
*/
525+
public Task<InputStream> getDataStreamInBackground(final ProgressCallback progressCallback) {
526+
final Task<Void>.TaskCompletionSource cts = Task.create();
527+
currentTasks.add(cts);
528+
529+
return taskQueue.enqueue(new Continuation<Void, Task<InputStream>>() {
530+
@Override
531+
public Task<InputStream> then(Task<Void> toAwait) throws Exception {
532+
return fetchInBackground(progressCallback, toAwait, cts.getTask()).onSuccess(new Continuation<File, InputStream>() {
533+
@Override
534+
public InputStream then(Task<File> task) throws Exception {
535+
return new FileInputStream(task.getResult());
536+
}
537+
});
538+
}
539+
}).continueWithTask(new Continuation<InputStream, Task<InputStream>>() {
540+
@Override
541+
public Task<InputStream> then(Task<InputStream> task) throws Exception {
542+
cts.trySetResult(null); // release
543+
currentTasks.remove(cts);
544+
return task;
545+
}
546+
});
547+
}
548+
549+
/**
550+
* Gets the data stream for this object in a background thread.
551+
*
552+
* @return A Task that is resolved when the data stream has been fetched.
553+
*/
554+
public Task<InputStream> getDataStreamInBackground() {
555+
return getDataStreamInBackground((ProgressCallback) null);
556+
}
557+
558+
/**
559+
* Gets the data stream for this object in a background thread. `progressCallback` is guaranteed
560+
* to be called with 100 before `dataStreamCallback` is called.
561+
*
562+
* @param dataStreamCallback
563+
* A GetDataCallback that is called when the get completes.
564+
* @param progressCallback
565+
* A ProgressCallback that is called periodically with progress updates.
566+
*/
567+
public void getDataStreamInBackground(GetDataStreamCallback dataStreamCallback,
568+
final ProgressCallback progressCallback) {
569+
ParseTaskUtils.callbackOnMainThreadAsync(
570+
getDataStreamInBackground(progressCallback), dataStreamCallback);
571+
}
572+
573+
/**
574+
* Gets the data stream for this object in a background thread.
575+
*
576+
* @param dataStreamCallback
577+
* A GetDataCallback that is called when the get completes.
578+
*/
579+
public void getDataStreamInBackground(GetDataStreamCallback dataStreamCallback) {
580+
ParseTaskUtils.callbackOnMainThreadAsync(getDataStreamInBackground(), dataStreamCallback);
581+
}
582+
583+
private Task<File> fetchInBackground(
584+
final ProgressCallback progressCallback,
585+
Task<Void> toAwait,
586+
final Task<Void> cancellationToken) {
587+
if (cancellationToken != null && cancellationToken.isCancelled()) {
588+
return Task.cancelled();
589+
}
590+
591+
return toAwait.continueWithTask(new Continuation<Void, Task<File>>() {
592+
@Override
593+
public Task<File> then(Task<Void> task) throws Exception {
594+
if (cancellationToken != null && cancellationToken.isCancelled()) {
595+
return Task.cancelled();
596+
}
597+
return getFileController().fetchAsync(
598+
state,
599+
null,
600+
progressCallbackOnMainThread(progressCallback),
601+
cancellationToken);
602+
}
603+
});
604+
}
605+
477606
/**
478607
* Cancels the current network request and callbacks whether it's uploading or fetching data from
479608
* the server.
@@ -490,7 +619,6 @@ public void cancel() {
490619
/*
491620
* Encode/Decode
492621
*/
493-
494622
@SuppressWarnings("unused")
495623
/* package */ ParseFile(JSONObject json, ParseDecoder decoder) {
496624
this(new State.Builder().name(json.optString("name")).url(json.optString("url")).build());

0 commit comments

Comments
 (0)