Skip to content

Commit d84edae

Browse files
authored
add Kotlin version and update UploadProgress recipe (#9033)
* add Kotlin version and update UploadProgress recipe
1 parent bc5ad23 commit d84edae

File tree

3 files changed

+448
-106
lines changed

3 files changed

+448
-106
lines changed

docs/recipes.md

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

0 commit comments

Comments
 (0)