I need to download a big file using firebase storage,
it is possible my user face network interruption through the download and i would like to be able to resume this download task.
FileDownloadTask downloadTask = firebaseStorage.getReferenceFromUrl(url).getFile(localFile);
downloadTask.addOnProgressListener(new OnProgressListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onProgress(FileDownloadTask.TaskSnapshot taskSnapshot) {
Log.v(TAG, "progress" + taskSnapshot.getBytesTransferred());;
}
});
downloadTask.addOnFailureListener(e -> {
CustomLogger.v(TAG, "downloadTask, on Failed: " + courseId);
deleteFilesAfterError(courseId);
});
downloadTask.addOnPausedListener(taskSnapshot
-> CustomLogger.v(TAG, "downloadTask, on paused: " + courseId));
the two last listener are never called. when i set up the complete listener:
downloadTask.addOnCompleteListener()
my app crashes.
even when i set up :
firebaseStorage.setMaxDownloadRetryTimeMillis(2000);
then switch off my network in the middle of a download, the downloadTask fail listener is not trigger. The task still seems to be "in progress" but there no data are downloaded. The documentation is poor on this feature. how am i supposed to implement it?
the fail listener seems broken
when i add a completeListener it crashes my app
firebaseStorage.setMaxDownloadRetryTimeMillis does not seems to have
any effect
any idea on how to tackle a resume feature for a file download?
When you say you switch off your network in the middle of the download, how are you doing this?
The reason I ask is because if you are leaving the activity temporarily to turn off the network stream then your problem might be an activity lifecycle problem.
If you leave the activity and do not handle this in the onPause(), onStop() and so on then you might experience this sort of behavior.
Other than that, your code looks similar to the docs (and my code that works fine), other than the fact that you didn't 'chain' your methods to add the listeners (shouldn't be a problem).
However, your code that you copied and pasted here is partially folded and does not show whether or not you are overiding the onFailure(Exception e) method, but I assume it is folded up in that arrow.
If you are still working on this, can you post the trace for any errors you're receiving on the crash?
Here is a block of code that works during network failure, just for a reference:
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageReference = storage.getReferenceFromUrl("gs://your-bucket/");
storageReference.getFile(localFile).addOnSuccessListener(YourActivity.this, new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
}
}
}).addOnFailureListener(YourActivity.this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
}
}
Related
I am downloading a json file from storage using 'getBytes', but I want to cancel the download if it took more than 10 seconds. the method 'getBytes' returns a a 'Task' type which doesn't have a cancel method, unlike 'getFile' which returns 'FileDownloadTask' that indeed has a cancel method.
So, Is there a way to cancel the download using 'getBytes', Can I cast 'Task' to 'FileDownloadTask' ?
Edit: Here is my code :
mainStorageRef.child(UNIVERSITIES_DATA_STORAGE_PATH).getBytes(Long.MAX_VALUE).addOnSuccessListener(new OnSuccessListener<byte[]>() {
#Override
public void onSuccess(byte[] bytes) {
String jsonData = new String(bytes, StandardCharsets.UTF_8);
...
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
FastUtils.toastAndLogConnectionFailure(context, e);
}
});
firebaser here
As far as I can see from the (closed source) implementation, the task that you get back from getBytes() is not a FileDownloadTask. It is instead a direct Task<byte[]> that is constructed by a TaskCompletionSource object. For that reason, it can't be cancelled.
Your request seems reasonable though, so I'd recommend filing a feature request to make the engineering team aware of it.
For the moment, I'd recommend using the getStream() method, which gives you a StreamDownloadTask task that can be cancelled. You can then read the stream contents into a ByteArrayOutputStream, which is pretty much what the getBytes method does internally.
I am showing Google's GDPR consent form and I am noticing a lot of these reports:
Fatal Exception: android.view.WindowManager$BadTokenException
Unable to add window -- token android.os.BinderProxy#38734f2 is not valid; is your activity running?
com.my.project.MainActivity$4.onConsentFormLoaded
As context I use MainActivity.this:
private void displayConsentForm() {
consentForm = new ConsentForm.Builder(MainActivity.this, GeneralUtils.getAppsPrivacyPolicy())
.withListener(new ConsentFormListener() {
#Override
public void onConsentFormLoaded() {
consentForm.show(); // crashing here for some users
}
#Override
public void onConsentFormOpened() { }
#Override
public void onConsentFormClosed(
ConsentStatus consentStatus, Boolean userPrefersAdFree) {
if(userPrefersAdFree) {
ConsentInformation.getInstance(MainActivity.this)
.setConsentStatus(NON_PERSONALIZED);
} else {
ConsentInformation.getInstance(MainActivity.this)
.setConsentStatus(consentStatus);
}
initAds();
}
#Override
public void onConsentFormError(String errorDescription) {
Log.e("Error",errorDescription);
}
})
.withPersonalizedAdsOption()
.withNonPersonalizedAdsOption()
.withAdFreeOption()
.build();
consentForm.load();
}
Here is additional Firebase crash report:
Why is this happening and how to prevent it? I am not sure what additional check to put before consentForm.show() and I can not reproduce the issue. Maybe it would suffice if I put this check before showing the form:
if(!MainActivity.this.isFinishing() && !MainActivity.this.isDestroyed())
?
The easiest way around this would be to just put a try-catch block around consentForm.show() and catch the BadTokenException.
It's not really clean, but it's likely that this is happening when the Activity finishes (maybe the user closes the app from Recents right as the Dialog is loading).
If this were my project, I'd first try adding that if statement you have (although you don't need the MainActivity.this. part; you can just call isFinishing() and isDestroyed() directly). Since you're referencing an Activity Context, this should take care of it.
However, if it still crashes, you should first look into reproducing it. Try getting to just before displayConsentForm() is called, then closing the app from Recents. Play around with the timing and you'll probably reproduce the crash. If not, then just add the try-catch. The Activity isn't displayed, since it's throwing that error, so the user isn't actually in the app.
I have a networkStateReceiver, that checks if I have internet or not.
If I do, I reinitiate instabug, if not, I want to deactivate. How can I do that?
I tried just setting it as null, but it doesn't work.
if(haveConnectedMobile || haveConnectedWifi){
//TODO will need to make a queue, and go through all that queue
PSLocationCenter.getInstance().initInstabug();
}else{
PSLocationCenter.getInstance().instabug = null;
}
This is my init:
public void initInstabug() {
String[] feedbackArray = getResources().getStringArray(R.array.feedback);
String randomStr = feedbackArray[new Random().nextInt(feedbackArray.length)];
Instabug.DEBUG = true;
instabug = Instabug.initialize(this)
.setAnnotationActivityClass(InstabugAnnotationActivity.class)
.setShowIntroDialog(true, PSTimelineActivity.class)
.enableEmailField(true, false)
.setEnableOverflowMenuItem(true)
.setDebugEnabled(true)
.setCommentRequired(true)
.setPostFeedbackMessage(randomStr)
.setPostBugReportMessage(randomStr) //TODO will be the post report message, random from array
.setCommentFieldHint("Please describe what went wrong")
.setPreSendingRunnable(new Runnable() {
#Override
public void run() {
String[] files = new String[2];
files[0] = Environment.getExternalStorageDirectory() + "/Passenger/passenger_log.txt";
files[1] = Environment.getExternalStorageDirectory() + "/Passenger/passenger_log2.txt";
Compress compress = new Compress(files, Environment.getExternalStorageDirectory() + "/Passenger/log.zip");
compress.zip(new CrudStateCallback() {
#Override
public void onResponse(String string) {
Log.i("", "ended making the archive");
}
});
}
})
.attachFileAtLocation(Environment.getExternalStorageDirectory() + "/Passenger/log.zip");
}
You can use this code to disable Instabug automatic invocation:
Instabug.getInstance().setInvocationEvent(IBGInvocationEvent.IBGInvocationEventNone)
This way it won't be invoked automatically. This will only affect the next Activity though (not the current one). You may force to stop and restart all listeners by calling onPause and onResume on the current Activity. (We may address that soon though, so that such changes are applied on the currently running Activity).
Don't forget to also enable the shake invocation event when internet access is restored.
Please keep in mind that Instabug SDK already caches all reports and will re-attempt to send them on next app launch until they're uploaded successfully.
Just wanted to post the updated answer.
The newer SDK has changed the name and now you can disable it by the following code:
Instabug.changeInvocationEvent(InstabugInvocationEvent.NONE)
Notice, if you want to disable it for entire application, just call this method in your Application class
I've noticed that occasionally images won't load in my app through picasso and that picasso is in fact erring. I am using two images per list item in a list view. Here's the picasso code:
Picasso.with(DashboardActivity.this).load(status).into(iv_customer_status_pic, new Callback() {
#Override public void onSuccess() {
Log.d("Debug", "Picasso Success");
}
#Override public void onError() {
Log.d("Debug", "Picasso Errored");
}
});
How can I ensure that the images are loaded, I don't want them to error and then make them disappear. Also why does it error? Is there a timeout? I noticed on more powerful devices it happens less.
The reasons why it fails might because of no Internet connection and Invalid Image URL.
With regard to the error handling refer to nPn's answer.
The reason the onError() callback for Picasso.with().load().into(target, callback) exists is because there is no 100% guarantee the load will be successful. For example if you are trying to load from a uri and you don't have an internet connection, the load will not be successful.
You can somehow attempt a re-try (which I think is already built into Picasso), but ultimately, you need to handle the case were the load fails (for whatever reason). One option would be to load a "default" image, like a generic "profile picture" if you were trying to load a specific users profile picture.
If you move the implementation of the callbacks to a separate class , or even the containing class you should be able to retry from the onError() call back. Here is what I am thinking:
class ContainingClass implements Callback.EmptyCallback
private int mRetryAttempts = 0;
#Override
public void onError() {
if (mRetryAttempts < 2) {
mRetryAttempts++;
// try again
} else {
mRetryAttempts = 0;
}
}
#Override
public void onSuccess() {
mRetryAttempts = 0;
}
I need to implement quite popular template of app behaviour - give opportunity to user to retry failed requests. Right now I catch failed request with SpiceServiceListener, and shows dialog where user can press "Retry" button. Unfortunately, using the same CachedSpiceRequest object with SpiceManager.execute() don't give desired behaviour, because RS removing all request listeners from mapRequestToLaunchToRequestListener if request wasn't successful. So request can work fine, but it will not return any information to my Activity.
Is there easy way (without modifying code of library) to implement this?
Unfortunately looks like there are no abstract solution for situation like this, so I had to add code like this in every request.
getSpiceManager().execute(r, new RequestListener<CountProfiles>() {
#Override
public void onRequestFailure(SpiceException spiceException) {
if (act.getSupportFragmentManager().findFragmentByTag("network_problem") == null) {
NetworkProblemDialogFragm.newInstance(r, this).show(act.getSupportFragmentManager(), "network_problem");
} else {
((NetworkProblemDialogFragm) act.getSupportFragmentManager().findFragmentByTag("network_problem")).setSpiceRequest(r);
((NetworkProblemDialogFragm) act.getSupportFragmentManager().findFragmentByTag("network_problem")).setRequestListener(this);
}
}
#Override
public void onRequestSuccess(CountProfiles countProfiles) {
}
});
NetworkProblemDialogFragm is a DialogFragment with Retry button, on click on this button I re execute failed request, using given RequestListener.
Not very beautiful solution, but looks like there no better one.