Why is my progress listener update callback not getting called in the OKHttp interceptor?
I've built a stripped down Android app to upload files to Amazon S3 using signed URLs. These URLs require a PUT call, which is slightly different than most file uploads which happen over POST.
I just paste in the S3 URL into the textview. I've verified the S3 URL works with this cURL command, so all is well with it.
curl -X PUT 'https://mybucket.s3.us-west-2.amazonaws.com/uploads/android/somevideo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credentia...0&X-Amz-Signature=213123123&X-Amz-SignedHeaders=host' --upload-file ~/Downloads/video.mp4
The file upload completes correctly inside the Android app, but I never get into my update
callback, so I cannot update the progress bar in the dialog.
Is there something different happening because I am doing a PUT request, and this is not a multipart form upload (I'm just sending the file as the body as an octet stream)?
My Activity code and the inner Progress class are all in one file below. When I set a breakpoint on line 126 (the update
function), I never enter it. I used the sample Progress listener linked here, but for some reason my code never is called.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final ProgressListener progressListener = new ProgressListener() {
@Override
public void update(long bytesRead, long contentLength, boolean done) {
if (done) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
@Override
public MediaType contentType() {
return responseBody.contentType();
}
@Override
public long contentLength() {
return responseBody.contentLength();
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
}
I've got two views. First, the main_activity.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/uploadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Upload File"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/uploadUrl"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ems="10"
android:hint="S3 URL, paste in here"
android:inputType="textMultiLine|textNoSuggestions"
app:layout_constraintBottom_toTopOf="@+id/uploadButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
upload_progress.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp">
<ProgressBar
android:id="@+id/uploadProgressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:max="100"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:progress="45" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="10dp"
android:text="Uploading file..."
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
app:layout_constraintBottom_toTopOf="@+id/uploadProgressBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread_inside" />
<TextView
android:id="@+id/uploadStatusMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="..."
android:textAppearance="@style/TextAppearance.AppCompat.Light.SearchResult.Title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/uploadProgressBar" />
</android.support.constraint.ConstraintLayout>
The Android manifest has the correct permissions for internet and I've enabled read permissions in the app permissions.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.putuploadwithprogress">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
android amazon-s3 okhttp okhttp3
add a comment |
I've built a stripped down Android app to upload files to Amazon S3 using signed URLs. These URLs require a PUT call, which is slightly different than most file uploads which happen over POST.
I just paste in the S3 URL into the textview. I've verified the S3 URL works with this cURL command, so all is well with it.
curl -X PUT 'https://mybucket.s3.us-west-2.amazonaws.com/uploads/android/somevideo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credentia...0&X-Amz-Signature=213123123&X-Amz-SignedHeaders=host' --upload-file ~/Downloads/video.mp4
The file upload completes correctly inside the Android app, but I never get into my update
callback, so I cannot update the progress bar in the dialog.
Is there something different happening because I am doing a PUT request, and this is not a multipart form upload (I'm just sending the file as the body as an octet stream)?
My Activity code and the inner Progress class are all in one file below. When I set a breakpoint on line 126 (the update
function), I never enter it. I used the sample Progress listener linked here, but for some reason my code never is called.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final ProgressListener progressListener = new ProgressListener() {
@Override
public void update(long bytesRead, long contentLength, boolean done) {
if (done) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
@Override
public MediaType contentType() {
return responseBody.contentType();
}
@Override
public long contentLength() {
return responseBody.contentLength();
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
}
I've got two views. First, the main_activity.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/uploadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Upload File"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/uploadUrl"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ems="10"
android:hint="S3 URL, paste in here"
android:inputType="textMultiLine|textNoSuggestions"
app:layout_constraintBottom_toTopOf="@+id/uploadButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
upload_progress.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp">
<ProgressBar
android:id="@+id/uploadProgressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:max="100"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:progress="45" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="10dp"
android:text="Uploading file..."
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
app:layout_constraintBottom_toTopOf="@+id/uploadProgressBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread_inside" />
<TextView
android:id="@+id/uploadStatusMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="..."
android:textAppearance="@style/TextAppearance.AppCompat.Light.SearchResult.Title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/uploadProgressBar" />
</android.support.constraint.ConstraintLayout>
The Android manifest has the correct permissions for internet and I've enabled read permissions in the app permissions.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.putuploadwithprogress">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
android amazon-s3 okhttp okhttp3
Is function read(Buffer sink, long byteCount) being called for each byte read?
– NIKHIL MAURYA
Nov 21 '18 at 9:11
@NIKHILMAURYA no, I'm not seeing that hit either
– xrd
Nov 21 '18 at 15:36
I think you are tracking progress of the response body not the request body. try to use BufferedSink method try this gist.github.com/kyawkyaw/54d9e2feb1c969c90673
– NIKHIL MAURYA
Nov 21 '18 at 16:17
add a comment |
I've built a stripped down Android app to upload files to Amazon S3 using signed URLs. These URLs require a PUT call, which is slightly different than most file uploads which happen over POST.
I just paste in the S3 URL into the textview. I've verified the S3 URL works with this cURL command, so all is well with it.
curl -X PUT 'https://mybucket.s3.us-west-2.amazonaws.com/uploads/android/somevideo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credentia...0&X-Amz-Signature=213123123&X-Amz-SignedHeaders=host' --upload-file ~/Downloads/video.mp4
The file upload completes correctly inside the Android app, but I never get into my update
callback, so I cannot update the progress bar in the dialog.
Is there something different happening because I am doing a PUT request, and this is not a multipart form upload (I'm just sending the file as the body as an octet stream)?
My Activity code and the inner Progress class are all in one file below. When I set a breakpoint on line 126 (the update
function), I never enter it. I used the sample Progress listener linked here, but for some reason my code never is called.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final ProgressListener progressListener = new ProgressListener() {
@Override
public void update(long bytesRead, long contentLength, boolean done) {
if (done) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
@Override
public MediaType contentType() {
return responseBody.contentType();
}
@Override
public long contentLength() {
return responseBody.contentLength();
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
}
I've got two views. First, the main_activity.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/uploadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Upload File"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/uploadUrl"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ems="10"
android:hint="S3 URL, paste in here"
android:inputType="textMultiLine|textNoSuggestions"
app:layout_constraintBottom_toTopOf="@+id/uploadButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
upload_progress.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp">
<ProgressBar
android:id="@+id/uploadProgressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:max="100"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:progress="45" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="10dp"
android:text="Uploading file..."
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
app:layout_constraintBottom_toTopOf="@+id/uploadProgressBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread_inside" />
<TextView
android:id="@+id/uploadStatusMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="..."
android:textAppearance="@style/TextAppearance.AppCompat.Light.SearchResult.Title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/uploadProgressBar" />
</android.support.constraint.ConstraintLayout>
The Android manifest has the correct permissions for internet and I've enabled read permissions in the app permissions.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.putuploadwithprogress">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
android amazon-s3 okhttp okhttp3
I've built a stripped down Android app to upload files to Amazon S3 using signed URLs. These URLs require a PUT call, which is slightly different than most file uploads which happen over POST.
I just paste in the S3 URL into the textview. I've verified the S3 URL works with this cURL command, so all is well with it.
curl -X PUT 'https://mybucket.s3.us-west-2.amazonaws.com/uploads/android/somevideo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credentia...0&X-Amz-Signature=213123123&X-Amz-SignedHeaders=host' --upload-file ~/Downloads/video.mp4
The file upload completes correctly inside the Android app, but I never get into my update
callback, so I cannot update the progress bar in the dialog.
Is there something different happening because I am doing a PUT request, and this is not a multipart form upload (I'm just sending the file as the body as an octet stream)?
My Activity code and the inner Progress class are all in one file below. When I set a breakpoint on line 126 (the update
function), I never enter it. I used the sample Progress listener linked here, but for some reason my code never is called.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final ProgressListener progressListener = new ProgressListener() {
@Override
public void update(long bytesRead, long contentLength, boolean done) {
if (done) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
@Override
public MediaType contentType() {
return responseBody.contentType();
}
@Override
public long contentLength() {
return responseBody.contentLength();
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
}
I've got two views. First, the main_activity.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/uploadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Upload File"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/uploadUrl"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ems="10"
android:hint="S3 URL, paste in here"
android:inputType="textMultiLine|textNoSuggestions"
app:layout_constraintBottom_toTopOf="@+id/uploadButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
upload_progress.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp">
<ProgressBar
android:id="@+id/uploadProgressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:max="100"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:progress="45" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="10dp"
android:text="Uploading file..."
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
app:layout_constraintBottom_toTopOf="@+id/uploadProgressBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread_inside" />
<TextView
android:id="@+id/uploadStatusMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="..."
android:textAppearance="@style/TextAppearance.AppCompat.Light.SearchResult.Title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/uploadProgressBar" />
</android.support.constraint.ConstraintLayout>
The Android manifest has the correct permissions for internet and I've enabled read permissions in the app permissions.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.putuploadwithprogress">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
android amazon-s3 okhttp okhttp3
android amazon-s3 okhttp okhttp3
asked Nov 21 '18 at 8:55
xrdxrd
1,97641825
1,97641825
Is function read(Buffer sink, long byteCount) being called for each byte read?
– NIKHIL MAURYA
Nov 21 '18 at 9:11
@NIKHILMAURYA no, I'm not seeing that hit either
– xrd
Nov 21 '18 at 15:36
I think you are tracking progress of the response body not the request body. try to use BufferedSink method try this gist.github.com/kyawkyaw/54d9e2feb1c969c90673
– NIKHIL MAURYA
Nov 21 '18 at 16:17
add a comment |
Is function read(Buffer sink, long byteCount) being called for each byte read?
– NIKHIL MAURYA
Nov 21 '18 at 9:11
@NIKHILMAURYA no, I'm not seeing that hit either
– xrd
Nov 21 '18 at 15:36
I think you are tracking progress of the response body not the request body. try to use BufferedSink method try this gist.github.com/kyawkyaw/54d9e2feb1c969c90673
– NIKHIL MAURYA
Nov 21 '18 at 16:17
Is function read(Buffer sink, long byteCount) being called for each byte read?
– NIKHIL MAURYA
Nov 21 '18 at 9:11
Is function read(Buffer sink, long byteCount) being called for each byte read?
– NIKHIL MAURYA
Nov 21 '18 at 9:11
@NIKHILMAURYA no, I'm not seeing that hit either
– xrd
Nov 21 '18 at 15:36
@NIKHILMAURYA no, I'm not seeing that hit either
– xrd
Nov 21 '18 at 15:36
I think you are tracking progress of the response body not the request body. try to use BufferedSink method try this gist.github.com/kyawkyaw/54d9e2feb1c969c90673
– NIKHIL MAURYA
Nov 21 '18 at 16:17
I think you are tracking progress of the response body not the request body. try to use BufferedSink method try this gist.github.com/kyawkyaw/54d9e2feb1c969c90673
– NIKHIL MAURYA
Nov 21 '18 at 16:17
add a comment |
1 Answer
1
active
oldest
votes
The issue was, as nikhil mentioned, that this was intercepting the response and not the request.
The interceptor needed to be changed this like:
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
This below full code works.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final CountingRequestBody.Listener progressListener = new CountingRequestBody.Listener() {
@Override
public void onRequestProgress(long bytesRead, long contentLength) {
if (bytesRead >= contentLength) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
class CountingRequestBody extends RequestBody {
protected RequestBody delegate;
protected Listener listener;
protected CountingSink countingSink;
public CountingRequestBody(RequestBody delegate, Listener listener) {
this.delegate = delegate;
this.listener = listener;
}
@Override public MediaType contentType() {
return delegate.contentType();
}
@Override public long contentLength() {
try {
return delegate.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
@Override public void writeTo(BufferedSink sink) throws IOException {
BufferedSink bufferedSink;
countingSink = new CountingSink(sink);
bufferedSink = Okio.buffer(countingSink);
delegate.writeTo(bufferedSink);
bufferedSink.flush();
}
protected final class CountingSink extends ForwardingSink {
private long bytesWritten = 0;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWritten += byteCount;
listener.onRequestProgress(bytesWritten, contentLength());
}
}
public static interface Listener {
public void onRequestProgress(long bytesWritten, long contentLength);
}
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53408345%2fwhy-is-my-progress-listener-update-callback-not-getting-called-in-the-okhttp-int%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The issue was, as nikhil mentioned, that this was intercepting the response and not the request.
The interceptor needed to be changed this like:
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
This below full code works.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final CountingRequestBody.Listener progressListener = new CountingRequestBody.Listener() {
@Override
public void onRequestProgress(long bytesRead, long contentLength) {
if (bytesRead >= contentLength) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
class CountingRequestBody extends RequestBody {
protected RequestBody delegate;
protected Listener listener;
protected CountingSink countingSink;
public CountingRequestBody(RequestBody delegate, Listener listener) {
this.delegate = delegate;
this.listener = listener;
}
@Override public MediaType contentType() {
return delegate.contentType();
}
@Override public long contentLength() {
try {
return delegate.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
@Override public void writeTo(BufferedSink sink) throws IOException {
BufferedSink bufferedSink;
countingSink = new CountingSink(sink);
bufferedSink = Okio.buffer(countingSink);
delegate.writeTo(bufferedSink);
bufferedSink.flush();
}
protected final class CountingSink extends ForwardingSink {
private long bytesWritten = 0;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWritten += byteCount;
listener.onRequestProgress(bytesWritten, contentLength());
}
}
public static interface Listener {
public void onRequestProgress(long bytesWritten, long contentLength);
}
}
add a comment |
The issue was, as nikhil mentioned, that this was intercepting the response and not the request.
The interceptor needed to be changed this like:
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
This below full code works.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final CountingRequestBody.Listener progressListener = new CountingRequestBody.Listener() {
@Override
public void onRequestProgress(long bytesRead, long contentLength) {
if (bytesRead >= contentLength) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
class CountingRequestBody extends RequestBody {
protected RequestBody delegate;
protected Listener listener;
protected CountingSink countingSink;
public CountingRequestBody(RequestBody delegate, Listener listener) {
this.delegate = delegate;
this.listener = listener;
}
@Override public MediaType contentType() {
return delegate.contentType();
}
@Override public long contentLength() {
try {
return delegate.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
@Override public void writeTo(BufferedSink sink) throws IOException {
BufferedSink bufferedSink;
countingSink = new CountingSink(sink);
bufferedSink = Okio.buffer(countingSink);
delegate.writeTo(bufferedSink);
bufferedSink.flush();
}
protected final class CountingSink extends ForwardingSink {
private long bytesWritten = 0;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWritten += byteCount;
listener.onRequestProgress(bytesWritten, contentLength());
}
}
public static interface Listener {
public void onRequestProgress(long bytesWritten, long contentLength);
}
}
add a comment |
The issue was, as nikhil mentioned, that this was intercepting the response and not the request.
The interceptor needed to be changed this like:
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
This below full code works.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final CountingRequestBody.Listener progressListener = new CountingRequestBody.Listener() {
@Override
public void onRequestProgress(long bytesRead, long contentLength) {
if (bytesRead >= contentLength) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
class CountingRequestBody extends RequestBody {
protected RequestBody delegate;
protected Listener listener;
protected CountingSink countingSink;
public CountingRequestBody(RequestBody delegate, Listener listener) {
this.delegate = delegate;
this.listener = listener;
}
@Override public MediaType contentType() {
return delegate.contentType();
}
@Override public long contentLength() {
try {
return delegate.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
@Override public void writeTo(BufferedSink sink) throws IOException {
BufferedSink bufferedSink;
countingSink = new CountingSink(sink);
bufferedSink = Okio.buffer(countingSink);
delegate.writeTo(bufferedSink);
bufferedSink.flush();
}
protected final class CountingSink extends ForwardingSink {
private long bytesWritten = 0;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWritten += byteCount;
listener.onRequestProgress(bytesWritten, contentLength());
}
}
public static interface Listener {
public void onRequestProgress(long bytesWritten, long contentLength);
}
}
The issue was, as nikhil mentioned, that this was intercepting the response and not the request.
The interceptor needed to be changed this like:
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
This below full code works.
package com.example.putuploadwithprogress;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView uploadUrl = findViewById(R.id.uploadUrl);
Button uploadButton = findViewById(R.id.uploadButton);
uploadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View layout = getLayoutInflater().inflate(R.layout.upload_progress, null);
final ProgressBar progress = layout.findViewById(R.id.uploadProgressBar);
builder.setView(layout);
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
final AlertDialog dialog = builder.show();
final String url = uploadUrl.getText().toString().trim();
try {
new Thread(new Runnable() {
@Override
public void run() {
String mimeType = "video/mp4";
String filename = Environment
.getExternalStoragePublicDirectory(Environment
.DIRECTORY_DOWNLOADS).toString() + "/video.mp4";
File file = new File(filename);
try {
new Progress(url, file, mimeType, MainActivity.this, progress, dialog).run();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.hide();
}
});
} catch (Exception e) {
System.out.println( "Got an error: " + e.getMessage());
MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { dialog.hide(); } });
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class Progress {
private String mime;
ProgressBar progressBar;
AlertDialog dialog;
Activity activity;
private String url;
private File file;
Progress(String _url,
File _file,
String _mime,
Activity _activity,
ProgressBar _progressBar,
AlertDialog _dialog) {
url = _url;
file = _file;
mime = _mime;
dialog = _dialog;
progressBar = _progressBar;
activity = _activity;
}
public void run() {
final Request request = new Request.Builder()
.header("Content-Type", mime)
.url(url)
.put(RequestBody.create(MediaType.parse(mime), file))
.build();
final CountingRequestBody.Listener progressListener = new CountingRequestBody.Listener() {
@Override
public void onRequestProgress(long bytesRead, long contentLength) {
if (bytesRead >= contentLength) {
if (dialog != null)
activity.runOnUiThread(new Runnable() {
public void run() {
dialog.hide();
}
});
} else {
if (contentLength > 0) {
final int progress = (int) (((double) bytesRead / contentLength) * 100);
if (progressBar != null)
activity.runOnUiThread(new Runnable() {
public void run() {
progressBar.setProgress(progress);
}
});
}
}
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null) {
return chain.proceed(originalRequest);
}
Request progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(),
new CountingRequestBody(originalRequest.body(), progressListener))
.build();
return chain.proceed(progressRequest);
}
})
.build();
try (Response response = client.newCall(request).execute()) {
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!response.isSuccessful()) {
String message = response.message();
Toast.makeText(activity, "Unable to upload file: " + message, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Uploaded file successfully", Toast.LENGTH_LONG).show();
}
dialog.hide();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
class CountingRequestBody extends RequestBody {
protected RequestBody delegate;
protected Listener listener;
protected CountingSink countingSink;
public CountingRequestBody(RequestBody delegate, Listener listener) {
this.delegate = delegate;
this.listener = listener;
}
@Override public MediaType contentType() {
return delegate.contentType();
}
@Override public long contentLength() {
try {
return delegate.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
@Override public void writeTo(BufferedSink sink) throws IOException {
BufferedSink bufferedSink;
countingSink = new CountingSink(sink);
bufferedSink = Okio.buffer(countingSink);
delegate.writeTo(bufferedSink);
bufferedSink.flush();
}
protected final class CountingSink extends ForwardingSink {
private long bytesWritten = 0;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWritten += byteCount;
listener.onRequestProgress(bytesWritten, contentLength());
}
}
public static interface Listener {
public void onRequestProgress(long bytesWritten, long contentLength);
}
}
answered Nov 21 '18 at 17:14
xrdxrd
1,97641825
1,97641825
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53408345%2fwhy-is-my-progress-listener-update-callback-not-getting-called-in-the-okhttp-int%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Is function read(Buffer sink, long byteCount) being called for each byte read?
– NIKHIL MAURYA
Nov 21 '18 at 9:11
@NIKHILMAURYA no, I'm not seeing that hit either
– xrd
Nov 21 '18 at 15:36
I think you are tracking progress of the response body not the request body. try to use BufferedSink method try this gist.github.com/kyawkyaw/54d9e2feb1c969c90673
– NIKHIL MAURYA
Nov 21 '18 at 16:17