Skip to content

Commit 28a3deb

Browse files
committed
add Kotlin version and update UploadProgress recipe
1 parent 0e03529 commit 28a3deb

File tree

3 files changed

+438
-106
lines changed

3 files changed

+438
-106
lines changed

docs/recipes.md

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,217 @@ Use `Response.challenges()` to get the schemes and realms of any authentication
947947
}
948948
```
949949

950+
### Upload Progress ([.kt][UploadProgressKotlin], [.java][UploadProgressJava])
951+
952+
Upload a file to a server (for example, Imgur) and report progress as the request body is being written. You can implement a ProgressListener to receive updates and wrap the original request body with ProgressRequestBody. This allows you to monitor how many bytes have been uploaded and calculate the percentage of completion.
953+
954+
=== ":material-language-kotlin: Kotlin"
955+
```kotlin
956+
class UploadProgress {
957+
companion object {
958+
private const val IMGUR_CLIENT_ID = "9199fdef135c122"
959+
private val MEDIA_TYPE_PNG: MediaType = "image/png".toMediaType()
960+
961+
@JvmStatic
962+
fun main(args: Array<String>) {
963+
UploadProgress().run()
964+
}
965+
}
966+
967+
private val client = OkHttpClient()
968+
969+
@Throws(Exception::class)
970+
fun run() {
971+
val progressListener = object : ProgressListener {
972+
var firstUpdate = true
973+
974+
override fun update(bytesWritten: Long, contentLength: Long, done: Boolean) {
975+
if (done) {
976+
println("completed")
977+
} else {
978+
if (firstUpdate) {
979+
firstUpdate = false
980+
if (contentLength == -1L) {
981+
println("content-length: unknown")
982+
} else {
983+
println("content-length: $contentLength")
984+
}
985+
}
986+
println(bytesWritten)
987+
if (contentLength != -1L) {
988+
println("${100 * bytesWritten / contentLength}% done")
989+
}
990+
}
991+
}
992+
}
993+
994+
val requestBody = RequestBody.create(
995+
MEDIA_TYPE_PNG,
996+
File("docs/images/logo-square.png")
997+
)
998+
999+
val request = Request.Builder()
1000+
.header("Authorization", "Client-ID $IMGUR_CLIENT_ID")
1001+
.url("https://api.imgur.com/3/image")
1002+
.post(ProgressRequestBody(requestBody, progressListener))
1003+
.build()
1004+
1005+
val response = client.newCall(request).execute()
1006+
if (!response.isSuccessful) throw IOException("Unexpected code $response")
1007+
1008+
println(response.body?.string())
1009+
}
1010+
1011+
private class ProgressRequestBody(
1012+
private val delegate: RequestBody,
1013+
private val progressListener: ProgressListener
1014+
) : RequestBody() {
1015+
1016+
override fun contentType(): MediaType? = delegate.contentType()
1017+
1018+
@Throws(IOException::class)
1019+
override fun contentLength(): Long = delegate.contentLength()
1020+
1021+
@Throws(IOException::class)
1022+
override fun writeTo(sink: BufferedSink) {
1023+
val bufferedSink = Okio.buffer(sink(sink))
1024+
delegate.writeTo(bufferedSink)
1025+
bufferedSink.flush()
1026+
}
1027+
1028+
fun sink(sink: Sink): Sink {
1029+
return object : ForwardingSink(sink) {
1030+
private var totalBytesWritten: Long = 0
1031+
private var completed: Boolean = false
1032+
1033+
@Throws(IOException::class)
1034+
override fun write(source: Buffer, byteCount: Long) {
1035+
super.write(source, byteCount)
1036+
totalBytesWritten += byteCount
1037+
progressListener.update(totalBytesWritten, contentLength(), completed)
1038+
}
1039+
1040+
@Throws(IOException::class)
1041+
override fun close() {
1042+
super.close()
1043+
if (!completed) {
1044+
completed = true
1045+
progressListener.update(totalBytesWritten, contentLength(), completed)
1046+
}
1047+
}
1048+
}
1049+
}
1050+
}
1051+
1052+
interface ProgressListener {
1053+
fun update(bytesWritten: Long, contentLength: Long, done: Boolean)
1054+
}
1055+
}
1056+
```
1057+
1058+
=== ":material-language-java: Java"
1059+
```java
1060+
public final class UploadProgress {
1061+
private static final String IMGUR_CLIENT_ID = "9199fdef135c122";
1062+
private static final MediaType MEDIA_TYPE_PNG = MediaType.get("image/png");
1063+
1064+
private final OkHttpClient client = new OkHttpClient();
1065+
1066+
public void run() throws Exception {
1067+
final ProgressListener progressListener = new ProgressListener() {
1068+
boolean firstUpdate = true;
1069+
1070+
@Override public void update(long bytesWritten, long contentLength, boolean done) {
1071+
if (done) {
1072+
System.out.println("completed");
1073+
} else {
1074+
if (firstUpdate) {
1075+
firstUpdate = false;
1076+
if (contentLength == -1) {
1077+
System.out.println("content-length: unknown");
1078+
} else {
1079+
System.out.format("content-length: %d\n", contentLength);
1080+
}
1081+
}
1082+
System.out.println(bytesWritten);
1083+
if (contentLength != -1) {
1084+
System.out.format("%d%% done\n", (100 * bytesWritten) / contentLength);
1085+
}
1086+
}
1087+
}
1088+
};
1089+
1090+
RequestBody requestBody = RequestBody.create(
1091+
new File("docs/images/logo-square.png"),
1092+
MEDIA_TYPE_PNG);
1093+
1094+
Request request = new Request.Builder()
1095+
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
1096+
.url("https://api.imgur.com/3/image")
1097+
.post(new ProgressRequestBody(requestBody, progressListener))
1098+
.build();
1099+
1100+
Response response = client.newCall(request).execute();
1101+
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
1102+
1103+
System.out.println(response.body().string());
1104+
}
1105+
1106+
public static void main(String... args) throws Exception {
1107+
new UploadProgress().run();
1108+
}
1109+
1110+
private static class ProgressRequestBody extends RequestBody {
1111+
private final ProgressListener progressListener;
1112+
private final RequestBody delegate;
1113+
1114+
public ProgressRequestBody(RequestBody delegate, ProgressListener progressListener) {
1115+
this.delegate = delegate;
1116+
this.progressListener = progressListener;
1117+
}
1118+
1119+
@Override public MediaType contentType() {
1120+
return delegate.contentType();
1121+
}
1122+
1123+
@Override public long contentLength() throws IOException {
1124+
return delegate.contentLength();
1125+
}
1126+
1127+
@Override public void writeTo(BufferedSink sink) throws IOException {
1128+
BufferedSink bufferedSink = Okio.buffer(sink(sink));
1129+
delegate.writeTo(bufferedSink);
1130+
bufferedSink.flush();
1131+
}
1132+
1133+
public Sink sink(Sink sink) {
1134+
return new ForwardingSink(sink) {
1135+
private long totalBytesWritten = 0L;
1136+
private boolean completed = false;
1137+
1138+
@Override public void write(Buffer source, long byteCount) throws IOException {
1139+
super.write(source, byteCount);
1140+
totalBytesWritten += byteCount;
1141+
progressListener.update(totalBytesWritten, contentLength(), completed);
1142+
}
1143+
1144+
@Override public void close() throws IOException {
1145+
super.close();
1146+
if (!completed) {
1147+
completed = true;
1148+
progressListener.update(totalBytesWritten, contentLength(), completed);
1149+
}
1150+
}
1151+
};
1152+
}
1153+
}
1154+
1155+
interface ProgressListener {
1156+
void update(long bytesWritten, long contentLength, boolean done);
1157+
}
1158+
}
1159+
```
1160+
9501161
[SynchronousGetJava]: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/SynchronousGet.java
9511162
[SynchronousGetKotlin]: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/kt/SynchronousGet.kt
9521163
[AsynchronousGetJava]: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/AsynchronousGet.java
@@ -975,3 +1186,5 @@ Use `Response.challenges()` to get the schemes and realms of any authentication
9751186
[PerCallSettingsKotlin]: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/kt/PerCallSettings.kt
9761187
[AuthenticateJava]: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/Authenticate.java
9771188
[AuthenticateKotlin]: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/kt/Authenticate.kt
1189+
[UploadProgressJava]: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/UploadProgress.java
1190+
[UploadProgressKotlin]: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/kt/UploadProgress.kt

0 commit comments

Comments
 (0)