Is it possible to show progress bar when upload image via Retrofit 2
Is it possible to show progress bar when upload image via Retrofit 2
I'am currently using Retrofit 2
and i want to upload some photo at my server. I know, that older version uses TypedFile
class for uploading. And if we want to use progress bar with it we should override writeTo
method in TypedFile
class.
Is it possible to show progress when using retrofit 2
library?
Answer by Shubham A. for Is it possible to show progress bar when upload image via Retrofit 2
As far as I can see in this post, no updates regarding the image upload progress response has been made and you still have to override
the writeTo
method as shown in this SO answer by making a ProgressListener
interface and using a sub-class of TypedFile
to override
the writeTo
method.
So, there isn't any built-in way to show progress when using retrofit 2 library.
Answer by Yuriy Kolbasinskiy for Is it possible to show progress bar when upload image via Retrofit 2
First of all, you should use Retrofit 2 version equal or above 2.0 beta2. Second, create new class extends RequestBody
:
public class ProgressRequestBody extends RequestBody { private File mFile; private String mPath; private UploadCallbacks mListener; private static final int DEFAULT_BUFFER_SIZE = 2048; public interface UploadCallbacks { void onProgressUpdate(int percentage); void onError(); void onFinish(); } public ProgressRequestBody(final File file, final UploadCallbacks listener) { mFile = file; mListener = listener; } @Override public MediaType contentType() { // i want to upload only images return MediaType.parse("image/*"); } @Override public long contentLength() throws IOException { return mFile.length(); } @Override public void writeTo(BufferedSink sink) throws IOException { long fileLength = mFile.length(); byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; FileInputStream in = new FileInputStream(mFile); long uploaded = 0; try { int read; Handler handler = new Handler(Looper.getMainLooper()); while ((read = in.read(buffer)) != -1) { // update progress on UI thread handler.post(new ProgressUpdater(uploaded, fileLength)); uploaded += read; sink.write(buffer, 0, read); } } finally { in.close(); } } private class ProgressUpdater implements Runnable { private long mUploaded; private long mTotal; public ProgressUpdater(long uploaded, long total) { mUploaded = uploaded; mTotal = total; } @Override public void run() { mListener.onProgressUpdate((int)(100 * mUploaded / mTotal)); } } }
Third, create interface
@Multipart @POST("/upload") Call uploadImage(@Part MultipartBody.Part file);
Now you can get progress of your upload.
In your activity
(or fragment
):
class MyActivity extends AppCompatActivity implements ProgressRequestBody.UploadCallbacks { ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); progressBar = findViewById(R.id.progressBar); ProgressRequestBody fileBody = new ProgressRequestBody(file, this); MultipartBody.Part filePart = MultipartBody.Part.createFormData("image", file.getName(), fileBody); Call request = RetrofitClient.uploadImage(filepart); request.enqueue(new Callback{...}); } @Override public void onProgressUpdate(int percentage) { // set current progress progressBar.setProgress(percentage); } @Override public void onError() { // do something on error } @Override public void onFinish() { // do something on upload finished // for example start next uploading at queue progressBar.setProgress(100); } }
Answer by iscariot for Is it possible to show progress bar when upload image via Retrofit 2
For retrofit 2.0.0-beta4 uploading files is not implemented correctly
parser source code for now
@Documented @Target(PARAMETER) @Retention(RUNTIME) public @interface Part { String value(); String encoding() default "binary"; } // ##### okhttp3.Headers headers = okhttp3.Headers.of( "Content-Disposition", "form-data; name=\"" + part.value() + "\"", "Content-Transfer-Encoding", part.encoding());
and there is no way to add filename by annotation
so we use this hack to insert filename
for now interface must be
@Multipart @POST("some/method") Observable> UpdateUserPhoto( // RxJava @Part("token") RequestBody token, @Part("avatar\"; filename=\"avatar.png") RequestBody photo );
and after build a request we take
Content-Disposition: form-data; name="avatar"; filename="avatar.png" Content-Transfer-Encoding: binary
RequestBody media type for file(image) must be
MediaType MEDIA_TYPE_IMAGE = MediaType.parse("image/*");
or something else in your option
Answer by Justin Fiedler for Is it possible to show progress bar when upload image via Retrofit 2
Here's how to handle upload file progress with a simple POST rather than Multipart. For multipart check out @Yariy's solution. Additionally, this solution uses Content URI's instead of direct file references.
RestClient
@Headers({ "Accept: application/json", "Content-Type: application/octet-stream" }) @POST("api/v1/upload") Call uploadFile(@Body RequestBody file);
ProgressRequestBody
public class ProgressRequestBody extends RequestBody { private static final String LOG_TAG = ProgressRequestBody.class.getSimpleName(); public interface ProgressCallback { public void onProgress(long progress, long total); } public static class UploadInfo { //Content uri for the file public Uri contentUri; // File size in bytes public long contentLength; } private WeakReference mContextRef; private UploadInfo mUploadInfo; private ProgressCallback mListener; private static final int UPLOAD_PROGRESS_BUFFER_SIZE = 8192; public ProgressRequestBody(Context context, UploadInfo uploadInfo, ProgressCallback listener) { mContextRef = new WeakReference<>(context); mUploadInfo = uploadInfo; mListener = listener; } @Override public MediaType contentType() { // NOTE: We are posting the upload as binary data so we don't need the true mimeType return MediaType.parse("application/octet-stream"); } @Override public void writeTo(BufferedSink sink) throws IOException { long fileLength = mUploadInfo.contentLength; byte[] buffer = new byte[UPLOAD_PROGRESS_BUFFER_SIZE]; InputStream in = in(); long uploaded = 0; try { int read; while ((read = in.read(buffer)) != -1) { mListener.onProgress(uploaded, fileLength); uploaded += read; sink.write(buffer, 0, read); } } finally { in.close(); } } /** * WARNING: You must override this function and return the file size or you will get errors */ @Override public long contentLength() throws IOException { return mUploadInfo.contentLength; } private InputStream in() throws IOException { InputStream stream = null; try { stream = getContentResolver().openInputStream(mUploadInfo.contentUri); } catch (Exception ex) { Log.e(LOG_TAG, "Error getting input stream for upload", ex); } return stream; } private ContentResolver getContentResolver() { if (mContextRef.get() != null) { return mContextRef.get().getContentResolver(); } return null; } }
To initiate the upload:
// Create a ProgressRequestBody for the file ProgressRequestBody requestBody = new ProgressRequestBody( getContext(), new UploadInfo(myUri, fileSize), new ProgressRequestBody.ProgressCallback() { public void onProgress(long progress, long total) { //Update your progress UI here //You'll probably want to use a handler to run on UI thread } } ); // Upload mRestClient.uploadFile(requestBody);
Warning, if you forget to override the contentLength() function you may receive a few obscure errors:
retrofit2.adapter.rxjava.HttpException: HTTP 503 client read error
Or
Write error: ssl=0xb7e83110: I/O error during system call, Broken pipe
Or
javax.net.ssl.SSLException: Read error: ssl=0x9524b800: I/O error during system call, Connection reset by peer
These are a result of RequestBody.writeTo() being called multiple times as the default contentLength() is -1.
Anyways this took a long time to figure out, hope it helps.
Useful links: https://github.com/square/retrofit/issues/1217
Answer by Troy Yuan-Ting Wu for Is it possible to show progress bar when upload image via Retrofit 2
I update progressbar onProgressUpdate. This code can get better performance.
@Override public void writeTo(BufferedSink sink) throws IOException { long fileLength = mFile.length(); byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; FileInputStream in = new FileInputStream(mFile); long uploaded = 0; try { int read; Handler handler = new Handler(Looper.getMainLooper()); int num = 0; while ((read = in.read(buffer)) != -1) { int progress = (int) (100 * uploaded / fileLength); if( progress > num + 1 ){ // update progress on UI thread handler.post(new ProgressUpdater(uploaded, fileLength)); num = progress; } uploaded += read; sink.write(buffer, 0, read); } } finally { in.close(); } }
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment