FileNotFoundException while uploading multiple images using Retrofit - android

I have a class that add a news with its images by Retrofit.
When Retrofit wants upload images, it shows me this error: FileNotFoundException
I have seen similar questions and answers but nothing was with multiple images.
So I could not find my solution and ask this question.
This is my Retrofit interface's method:
#POST("News/SaveNews")
Call<GetResualt> setNewsLetter(#Body NewsLetterModel newsLetter);
#Multipart
#POST("Products/Post")
Call<GetResualt> uploadNewsLetterImage(#Query("ProductID") String newsLetterId,
#Query("CompanyID") String coId,
#Query("UserID") String uID,
#Query("Token") String token,
#Part List<MultipartBody.Part> files);
This is my onActivityResult after image selecting:
ActivityResultLauncher<Intent> mLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
if (result.getData() != null) {
if (result.getData().getClipData() != null) {
int count = result.getData().getClipData().getItemCount();
int currentItem = 0;
while (currentItem < count) {
Uri imageUri = result.getData().getClipData().getItemAt(currentItem).getUri();
imageUriList.add(imageUri);
partNames.add(currentItem + "");
currentItem++;
}
} else if (result.getData().getData() != null) {
imageUriList.add(result.getData().getData());
}
}
NewsLetterModel newsLetter = new NewsLetterModel();
newsLetter.setActiveComment(false);
newsLetter.setActiveLike(false);
newsLetter.setActiveSave(false);
newsLetter.setCategory(category);
newsLetter.setCompanyId(BaseCodeClass.CompanyID);
newsLetter.setCreatorId(BaseCodeClass.userID);
newsLetter.setLinkOut("");
newsLetter.setLinkToInstagram("");
newsLetter.setNewsDescription(description);
newsLetter.setNewsTitle(title);
newsLetter.setShow(true);
newsLetter.setSpare1("#FFFFFF");
newsLetter.setSpare2("#FFFFFF");
newsLetter.setSpare3("#FFFFFF");
newsLetter.setToken(BaseCodeClass.token);
newsLetter.setUserId(BaseCodeClass.userID);
uploadNewsLetter(newsLetter);
}
}
);
This is uploadNewsLetter():
private void uploadNewsLetter(NewsLetterModel newsLetter) {
Retrofit retrofit;
JsonApi api;
retrofit = RetrofitInstance.getRetrofit();
api = retrofit.create(JsonApi.class);
Call<GetResualt> call = api.setNewsLetter(newsLetter);
call.enqueue(new Callback<GetResualt>() {
#Override
public void onResponse(Call<GetResualt> call, Response<GetResualt> response) {
if (response.body().getResualt().equals("100")) {
String newsId = response.body().getMsg();
List<MultipartBody.Part> files;
files = convertUriToFIle(partNames, imageUriList);
uploadNewsImages(newsId, files);
}
}
#Override
public void onFailure(Call<GetResualt> call, Throwable t) {
Log.e("Error", t.getMessage());
}
});
}
This is convertUriToFIle()
private List<MultipartBody.Part> convertUriToFIle(List<String> partNames, List<Uri> imageUriList) {
List<MultipartBody.Part> files = new ArrayList<>();
for (int i = 0; i < imageUriList.size(); i++) {
File file = new File(imageUriList.get(i).getPath());
RequestBody requestFile = RequestBody.create(MediaType.parse(FileUtils.MIME_TYPE_IMAGE), file);
files.add(MultipartBody.Part.createFormData(partNames.get(i), file.getName(), requestFile));
}
return files;
}
And This is uploadNewsMessage:
private void uploadNewsImages(String newsLetterId, List<MultipartBody.Part> files) {
Retrofit retrofit;
JsonApi api;
retrofit = RetrofitInstance.getRetrofit();
api = retrofit.create(JsonApi.class);
Call<GetResualt> call = api.uploadNewsLetterImage(newsLetterId, BaseCodeClass.CompanyID, BaseCodeClass.userID, BaseCodeClass.token, files);
call.enqueue(new Callback<GetResualt>() {
#Override
public void onResponse(Call<GetResualt> call, Response<GetResualt> response) {
if (response.body().getResualt().equals("100")) {
Toast.makeText(getContext(), "خبر با موفقیت ثبت شد", Toast.LENGTH_SHORT).show();
} else {
Log.e("Error", response.body().getResualt() + " " + response.body().getMsg());
}
}
#Override
public void onFailure(Call<GetResualt> call, Throwable t) {
Log.e("Error", t.getMessage());
}
});
}
So base on my code, at first application uploads news and other stuffs except of images, after that it uploads images.
But when it wants upload images it goes to onFailur of retrofit and shows me this error: FileNotFoundException.

In convertUriToFIle() use FileUtils.getFile(context,uri) instead of new File(imageUriList.get(i).getPath());

Related

Sending multiple files using multipart.Part

I am trying to send multiple files(images) in gmail but i am not able to send it. I have tried putting the multipart in array but instead of going files in a single mail, two mails are being delivered. My code is as below:
Interface:
public interface EmailService {
#Multipart
#POST("/send/email")
Call<OnlineAushadiModel> sendEmailOnlineAushadi(
#Part("FROM") RequestBody requestFrom,
#Part("TO") RequestBody requestTo,
#Part("SUBJECT") RequestBody requestSubject,
#Part("MailContain") RequestBody requestMailContain,
#Part("FileName") RequestBody requestFileName,
}
The main Activity:
private void sendData(HashMap<Integer, String> buttons) {
Date today = Calendar.getInstance().getTime();
to = RequestBody.create(MediaType.parse("text/plain"), "to");
from = RequestBody.create(MediaType.parse("text/plain"), "bajracharyasudeep#gmail.com");
subject = RequestBody.create(MediaType.parse("text/plain"), "You have received a new Order.");
content = RequestBody.create(MediaType.parse("text/plain"),
"Name: " + HomeActivity.username + "\n" +
"Contact Number: " + HomeActivity.phoneNumber + "\n" +
"Order date and Time: " + today + "\n" +
"Address For Delivery: " + etDeliveryAddress.getText().toString());
fileName = RequestBody.create(MediaType.parse("text/plain"),"hello");
fileToUpload = new MultipartBody.Part[buttons.size()];
for(int i = 0; i<buttons.size();i++){
Log.e("btnValue", buttons.get(i) + "");
File file = new File(buttons.get(i));
RequestBody mFile = RequestBody.create(MediaType.parse("image/" + fileExtension), file);
fileToUpload[i] = MultipartBody.Part.createFormData("file", file.getName(), mFile);
emailService = ApiClient.getApiClientOnlineAushadi().create(EmailService.class);
Call<OnlineAushadiModel> fileUpload = (Call<OnlineAushadiModel>) emailService.sendEmailOnlineAushadi(to,from,subject,content,fileName,fileToUpload[i]);
fileUpload.enqueue(new Callback<OnlineAushadiModel>() {
#Override
public void onResponse(Call<OnlineAushadiModel> call, Response<OnlineAushadiModel> response) {
Toast.makeText(getActivity(), "Success " + response.message(), Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(Call<OnlineAushadiModel> call, Throwable t) {
Log.e("error",t.getMessage() + "");
}
});
}
I have tried other methods such as putting the api call out of the loop but it still didnot helped. Can anybody please help me to send multiple files in Multipart?
You should not upload the file in the loop. Like the code example!
private void CallAPI() {
boolean HaveFile;
final ProgressDialog pd = new ProgressDialog(this);
pd.setMessage("Uploading...");
pd.setCancelable(false);
pd.show();
ArrayList<MultipartBody.Part> body = new ArrayList<>();
//image path is a string list of seleted files path
if (imagePath.size() != 0) {
for (int i = 0; i < imagePath.size(); i++) {
//creating a file
File file = new File(imagePath.get(i));
//creating request body for file
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
body.add(MultipartBody.Part.createFormData("uploaded_file", file.getName(), requestFile));
}
HaveFile=true;
} else {
RequestBody attachmentEmpty = RequestBody.create(MediaType.parse(/*"multipart/form-data"*/"text/plain"), "");
body.add( MultipartBody.Part.createFormData(/*"uploaded_file"*/"attachment", "0736E389-EF21-4286-BEBF-14CCD48B04A6", attachmentEmpty));
HaveFile=false;
}
APIService service =
ServiceGenerator.getclient().create(APIService.class);
Call<String> call = service.uploadMulFiles(body.size() == 0 ? null : body ,to,from,subject,content,fileName);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(#Nullable Call<String> call,
#Nullable Response<String> response) {
if (response != null) {
if (response.isSuccessful()) {
MainActivity.ComObj.ShowToast(activity_new_ticket.this, response.body() + "", Toast.LENGTH_SHORT);
ResetWidjet();
pd.cancel();
} else {
try {
assert response.errorBody() != null;
MainActivity.ComObj.ShowToast(activity_new_ticket.this, response.errorBody().string(), Toast.LENGTH_LONG);
} catch (IOException e) {
e.printStackTrace();
}
pd.cancel();
}
}
}
#Override
public void onFailure(#Nullable Call<String> call,#Nullable Throwable t) {
if (t != null) {
MainActivity.ComObj.ShowToast(activity_new_ticket.this, t.getMessage(), Toast.LENGTH_SHORT);
}
pd.cancel();
}
});
}
Hope this will help you

How do I run the Android Worker when the app is killed?

I am currently recording a video on a device, compressing this video and then uploading the compressed video to the server using Retrofit 2. I am also using the Worker class to perform all this in the background. A Progress is also being displayed in the notification bar while the upload is happening. My problem is when the app is Killed the entire upload process stops. I have tried to return WorkerResult.RETRY, which does work but it just repeats and thus one file is uploaded multiple times.The code is mentioned below :
Worker Class
public class UploadWorker extends Worker implements ProgressRequestBody.UploadCallBacks {
private static final String LOG_TAG = UploadWorker.class.getSimpleName();
public static final int UPDATE_PROGRESS = 8344;
Context context;
WorkerParameters parameters;
private static final String SERVER_PATH = "";
String filePath;
/*For notification update*/
private NotificationCompat.Builder notificationBuilder;
private NotificationManager notificationManager;
public UploadWorker(Context context,
WorkerParameters parameters) {
super(context, parameters);
this.context = context;
this.parameters = parameters;
}
#NonNull
#Override
public Result doWork() {
showNotificationUpdate();
compressVideo(getInputData().getString("currentPhotoPath");,
getInputData().getString("fileDestination"););
constructFile(filePath);
// Indicate success or failure with your return value:
return Result.SUCCESS;
}
private void uploadVideoToServer(File fileToUpload) {
ProgressRequestBody fileBody = new ProgressRequestBody(fileToUpload, this);
Gson gson = new GsonBuilder()
.setLenient()
.create();
MultipartBody.Part vFile = MultipartBody.Part.createFormData("fileToUpload", fileToUpload.getName(), fileBody);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SERVER_PATH)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(provideClient())
.build();
VideoInterface vInterface = retrofit.create(VideoInterface.class);
Call<ResponseBody> serverCom = vInterface.uploadVideo(vFile);
serverCom.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
if (response.body() != null) {
Log.d(LOG_TAG, "Resposne == " + response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
Log.d(LOG_TAG, "Response In String == " + response);
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(LOG_TAG, "Error == " + t.getLocalizedMessage());
}
});
}
#Override
public void onProgressUpdate(int percentage) {
updateNotification(percentage);
}
#Override
public void onError() {
sendProgressUpdate(false);
}
#Override
public void onFinish() {
sendProgressUpdate(true);
notificationManager.cancel(0);
notificationBuilder.setProgress(0, 0, false);
notificationBuilder.setContentTitle("Upload Done");
notificationBuilder.setSmallIcon(android.R.drawable.stat_sys_upload_done);
notificationManager.notify(0, notificationBuilder.build());
}
}
This is how I am setting up the worker in my activity
Data inputData = new Data.Builder()
.putString("currentPhotoPath", mCurrentPhotoPath)
.putString("fileDestination", f.getPath())
.build();
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresStorageNotLow(true)
.build();
OneTimeWorkRequest compressionWork =
new OneTimeWorkRequest.Builder(UploadWorker.class)
.setConstraints(constraints)
.addTag("CompressVideo")
.setInputData(inputData)
.build();
WorkManager.getInstance()
.enqueue(compressionWork);
WorkManager.getInstance().getStatusById(compressionWork.getId())
.observe(this, new Observer<WorkStatus>() {
#Override
public void onChanged(#Nullable WorkStatus workStatus) {
Log.d(LOG_TAG, "WORKER STATE == " + workStatus.getState().name());
if (workStatus != null && workStatus.getState().isFinished()) {
Log.d(LOG_TAG, "Is WOrk Finished == " + workStatus.getState().isFinished());
}
}
});
Can someone please help me out in finding an appropriate solution so that when the app is closed, the file upload still continues and stops when it is done?

Retrofit 2 image upload

in fact I am in the process of preparing an android application that makes the upload of an image on a server thanks to a REST API.
I tested lapi with POSTMAN and I have no errors.
but have an error in this part: I that the crash app before intent
this is my source codes:
public class FileShooser extends AppCompatActivity {
private static final int INTENT_REQUEST_CODE = 100;
private String name ;
private CompositeSubscription mSubscriptions;
ProgressDialog progressdialog ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSubscriptions = new CompositeSubscription();
// get name from last activity
name= getIntent().getStringExtra("Name");
// start file shooser intent
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
try {
startActivityForResult(intent, INTENT_REQUEST_CODE );
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==INTENT_REQUEST_CODE)
{
if(resultCode==RESULT_OK){
uploadImage( data.getData());
}
}
}
public byte[] getBytes(InputStream is) throws IOException {
ByteArrayOutputStream byteBuff = new ByteArrayOutputStream();
int buffSize = 1024;
byte[] buff = new byte[buffSize];
int len = 0;
while ((len = is.read(buff)) != -1) {
byteBuff.write(buff, 0, len);
}
return byteBuff.toByteArray();
}
private void uploadImage(Uri fileUri) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitInterface retrofitInterface = retrofit.create(RetrofitInterface.class);
// use the FileUtils to get the actual file by uri
File file = new File(fileUri.getPath());
showSnackBarMessage("name:"+file.getName());
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(
MediaType.parse(getContentResolver().getType(fileUri)),
file
);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("image", file.getName(), requestFile);
// progress dialog
progressdialog = new ProgressDialog(getApplicationContext());
progressdialog.setMessage("Please wait ...");
progressdialog.show();
retrofitInterface.upload(name,body).observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(this::handleResponse,this::handleError);
}
private void handleError(Throwable error) {
progressdialog.dismiss();
if (error instanceof HttpException) {
Gson gson = new GsonBuilder().create();
try {
String errorBody = ((HttpException) error).response().errorBody().string();
Response response = gson.fromJson(errorBody,Response.class);
showSnackBarMessage(response.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
} else {
showSnackBarMessage("Network Error !");
}
}
private void handleResponse(Response response) {
progressdialog.dismiss();
showSnackBarMessage(response.getMessage());
}
private void showSnackBarMessage(String message) {
Toast.makeText(getApplicationContext(),message,Toast.LENGTH_LONG).show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
}
thank you very much for your answers

How to make retrofit api request for each item in list with rxjava?

I'm very new to RxJava and although I have seen multiple questions related to the one I am asking, I can't seem to piece them out altogether.
I have a PostPatrol object containing the following data:
public class PostPatrol {
String checkpoint_name;
String status;
int user;
String detail;
List<String> photos;
public PostPatrol(int cpId, String checkpoint_name, String detail, List<String> photos, String detail) {
this.cpId = cpId;
this.checkpoint_name = checkpoint_name;
this.detail = detail;
this.photos = photos;
this.status = status;
}
//getters and setters
}
What I'm trying to do now is to save a local list of photos into this PostPatrol record, but before that I have to upload the photos one by one with retrofit, get back a url and save that to a list which I then set as the photos for the PostPatrol record.
Once I save all the needed details for a certain PostPatrol record, I then send that again through retrofit.
Currently, I am doing it this way:
I pass the photos to a function to upload the image one by one
The function is like this:
private void uploadImage(List<String> photos, String folder, long requestId) {
final int size = photos.size();
final long reqId = requestId;
for (String path : photos) {
File file = new File(path);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestBody);
RequestBody folderName = RequestBody.create(MediaType.parse("text/plain"), folder);
ApiEndpointInterface apiEndpointInterface = RetrofitManager.getApiInterface();
Call<FileInfo> call4File = apiEndpointInterface.postFile(body, folderName);
call4File.enqueue(new ApiCallback<FileInfo>() {
#Override
protected void do4Failure(Throwable t) {
Log.d(TAG, t.toString());
snackbar = Snackbar.make(viewPendingRequestLayout, R.string.sb_image_upload_error, Snackbar.LENGTH_SHORT);
snackbar.show();
position++;
}
#Override
protected void do4PositiveResponse(Response<FileInfo> response) {
Log.d(TAG, "Uploaded Image");
FileInfo fileDetails = response.body();
listUrls.add(fileDetails.getImage());
position++;
if (position == size) {
postRequest(reqId);
position = 0;
}
}
#Override
protected void do4NegativeResponse(Response<FileInfo> response) {
String bodyMsg = "";
try {
bodyMsg = new String(response.errorBody().bytes());
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, bodyMsg);
snackbar = Snackbar.make(viewPendingRequestLayout, R.string.sb_image_upload_error, Snackbar.LENGTH_SHORT);
snackbar.show();
position++;
}
});
}
}
In do4PositiveResponse I use local variables to keep track whether I have uploaded all the photos before sending them to a function where the list is saved to the PostPatrol record. Sometimes though, I get problems where the photos aren't uploaded at all since it fires too late or too early.
This is my code onpostRequest()
private void postRequest(long requestId) {
if(mapIdPatrol.containsKey(requestId)){
PostPatrol postPatrol = mapIdPatrol.get(requestId);
postPatrol.setPhotos(listUrls);
postPatrolRequest(postPatrol, requestId);
}
listUrls = new ArrayList<>();
}
And finally my code on postPatrolRequest()
private void postPatrolRequest(final PostPatrol postPatrol, final long requestId){
ApiEndpointInterface apiEndpointInterface = RetrofitManager.getApiInterface();
Call<ResponseId> call4Handle = apiEndpointInterface.handleCheckpoint(postPatrol);
call4Handle.enqueue(new ApiCallback<ResponseId>() {
#Override
protected void do4Failure(Throwable t) {
finishUploading();
Log.d(TAG, t.toString());
}
#Override
protected void do4PositiveResponse(Response<ResponseId> response) {
RequestsDataSource.removeRequest(getApplication(),requestId);
finishUploading();
}
#Override
protected void do4NegativeResponse(Response<ResponseId> response) {
finishUploading();
String bodyMsg = "";
try {
bodyMsg = new String(response.errorBody().bytes());
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, bodyMsg);
snackbar = Snackbar.make(viewPendingRequestLayout, getResources().getText(R.string.sb_negative_response), Snackbar.LENGTH_SHORT);
snackbar.show();
}
});
}
I know this is very inefficient and so I would like your help so I can try to find a way around it with the use of RxJava. Thank you.
Is the operation atomic? i.e. if saving some of the photos via Retrofit fails, do you still have to proceed?
Anyway, roughly the solution will be something like that (pseudocode):
Observable<String> urls = Observable.from(listOfPhotoFilePaths)
.flatMapDelayError(path -> { return retrofit.save(readFile(path))})
.toList()
Observable<PostPatrol> pp = urls
.map(list -> { return new PostPatrol(list)})

How to retry the request every hour for 5 attempts in rxjava and retrofit

I am trying to figure out how i can resubscribe the same observable for every hour when we have got an error from server for 5 attempts.I know about retryWhen but really not able to understand how i can use it in my case.I am using retrofit for server calls and rxjava to subscribe.
Here is the method where i am making a call using retrofit.Please help with this.
#Override
public Observable<Integer> uploadFileToServer(FileUploadData fileUploadData, File file) {
// log.i(TAG, "uploadFileToServer");
FileUploadEndpoint fileUploadEndpoint = null;
try {
fileUploadEndpoint = retrofitServiceFactory.getService(FileUploadEndpoint.class);
} catch (BaseUrlNotFoundException e) {
e.printStackTrace();
// log.i(TAG, "uploadFileToServer" + e.getMessage());
return Observable.just(FileUploadConstants.EXCEPTION_FILE_UPLOAD);
}
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(okhttp3.MultipartBody.FORM, file);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("uploadfile", file.getName(), requestFile);
// add another part within the multipart request
String descriptionString = "file upload";
RequestBody description =
RequestBody.create(
okhttp3.MultipartBody.FORM, descriptionString);
Map<String, String> queryMap = new HashMap<>();
queryMap.put("SENDER", fileUploadData.getSender());
queryMap.put("SOURCE", fileUploadData.getSource());
queryMap.put("SCHEMEID", fileUploadData.getSchemeId());
queryMap.put("ISPROCESSINGREQ", "false");
queryMap.put("ISENCRYPTED", "true");
queryMap.put("UID", fileUploadData.getSchemeId());
queryMap.put("METADATA", fileUploadData.getMetaData());
final Observable<FileUploadResponse> requestObservable = fileUploadEndpoint.upload(queryMap, description, body);
return requestObservable.map(new Function<FileUploadResponse, Integer>() {
#Override
public Integer apply(FileUploadResponse fileUploadResponse) throws Exception {
if (fileUploadResponse != null) {
int code = fileUploadResponse.getStatusCode();
switch (code) {
case 100:
return FileUploadConstants.FILE_UPLOAD_SUCCESSFUL;
}
}
return FileUploadConstants.EXCEPTION_FILE_UPLOAD;
}
}).retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
return throwableObservable.zipWith(Observable.range(1, 5), new BiFunction<Throwable, Integer, FileUploadResponse>() {
#Override
public FileUploadResponse apply(Throwable throwable, Integer integer) throws Exception {
return null;//not able to write the logic :(
}
});
}
});
}
#Override
public void setBaseUrl(String baseUrl) {
retrofitServiceFactory.setBaseUrl(baseUrl);
}
private interface FileUploadEndpoint {
#Multipart
#POST("da/appupload/file")
Observable<FileUploadResponse> upload(#QueryMap Map<String, String> additionValues,
#Part("description") RequestBody description,
#Part MultipartBody.Part file);
}
Here's a recipe for you.
public class RetryWithDelay implements
Func1<Observable<? extends Throwable>, Observable<?>> {
private static final String TAG = "RetryWithDelay";
private static final int DEFAULT_RETRY_COUNT = 5;
private static final int DEFAULT_RETRY_DELAY = 1000 * 60;
private final int maxRetries;
private final int retryDelayMillis;
private int retryCount;
public RetryWithDelay() {
this.maxRetries = DEFAULT_RETRY_COUNT;
this.retryDelayMillis = DEFAULT_RETRY_DELAY;
this.retryCount = 0;
}
public RetryWithDelay(final int maxRetries, final int retryDelayMillis) {
this.maxRetries = maxRetries;
this.retryDelayMillis = retryDelayMillis;
this.retryCount = 0;
}
#Override
public Observable<?> call(Observable<? extends Throwable> attempts) {
return attempts.flatMap(new Func1<Throwable, Observable<?>>() {
#Override
public Observable<?> call(Throwable throwable) {
if (throwable instanceof HttpException) {
LOGD(TAG, "Caught http exception.");
}
if (throwable instanceof IOException) {
LOGD(TAG, "Network error");
}
if (++retryCount < maxRetries) {
// When this Observable calls onNext, the original
// Observable will be retried (i.e. re-subscribed).
return Observable.timer(retryDelayMillis, TimeUnit.MILLISECONDS);
}
// Max retries hit. Just pass the error along.
return Observable.error(throwable);
}
});
}
}
Then in your code use it like this
// Leave constructor empty for default values
.retryWhen(new RetryWithDelay());
// Or setup different values
// In this case retry 3 times, with 5s delay
.retryWhen(new RetyryWithDelay(3, 5000));

Categories

Resources