7

I am currently building an app that saves the user's blog post in Firestore server. Everything is working fine, but I found out that the post was not uploaded under the unstable internet connection.

I tried to set a timeout to the Firestore instance, but it seems like there's no timeout option for Firestore library. The problem is, because there's no timeout setting, the app doesn't know when to dismiss the uploading screen (Spinner dialog).

I was thinking about creating a Handler or Observable or Thread and setting the timeout manually. After the specified timeout period, let the app dismiss the uploading screen. However, Firestore client will keep retrying the upload in the background even after the timeout. So this approach won't be suitable for this case...

Is there any solution for this? If I can set the timeout for the Firestore client itself, meaning letting the client to call onFailure() after the given timeout period, I can just save the post as draft in the local storage and try it again when the device is back to stable connection.

WasabiTea
  • 389
  • 2
  • 10

2 Answers2

4

Firestore will immediately add the document to its local cache. It will then try to synchronize that document with the server. To detect whether it will be able to do so, have a look at Gastón's answer.

To detect when the document has been written to the server, use a SuccessListener. This example from the Firestore documentation on adding documents shows how:

// Add a new document with a generated id.
Map<String, Object> data = new HashMap<>();
data.put("name", "Tokyo");
data.put("country", "Japan");

db.collection("cities")
        .add(data)
        .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
            @Override
            public void onSuccess(DocumentReference documentReference) {
                Log.d(TAG, "DocumentSnapshot written with ID: " + documentReference.getId());
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "Error adding document", e);
            }
        });
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • 2
    The onFailure listener is never called if the device is offline or unstable internet, even though offline persistence is disabled. – Aayush Taneja Jul 18 '18 at 17:42
  • The `onSuccess` or `onFailure` will only be called if there is a connection to the server. – Frank van Puffelen Jul 18 '18 at 18:49
  • Ohh.. ok. So is there any way to handle the case where due to some reason like unstable or no internet, the phone is unable to connect to the server? – Aayush Taneja Jul 18 '18 at 18:52
  • The Firestore client will auto-handle that situation, and synchronize the changes to the server once the connection is reestablished. It sounds like a [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) right now. What are you trying to accomplish with this code? – Frank van Puffelen Jul 18 '18 at 18:57
  • Im trying to upload the data at the moment when it is initiated (and not later when internet is reconnected) and the code to throw and exception or failure callback in case when the app is not able to connect with the server at that time. – Aayush Taneja Jul 18 '18 at 19:00
  • That's simply not how a completion listener works in Firestore. They only fire once the data has either been committed or rejected on the server. The database is designed to continue working in this situation, and I'd recommend to aim for the same logic in your app. For more on this see: https://stackoverflow.com/q/49068084, https://stackoverflow.com/q/47397547, https://stackoverflow.com/q/47718369, https://stackoverflow.com/a/51005660, https://stackoverflow.com/a/50918221 – Frank van Puffelen Jul 19 '18 at 03:38
  • Thanks. I will take a look. – Aayush Taneja Jul 19 '18 at 04:38
2

The best way of doing this is attaching a boolean that will let you know if you have internet before doing something (this is just to dismiss your spinner, as firestore has offline features like realtime database)

public static boolean hasActiveInternetConnection(Context context) {
    if (isNetworkAvailable(context)) {
        try {
            HttpURLConnection urlc = (HttpURLConnection) (new URL("http://www.google.com").openConnection());
            urlc.setRequestProperty("User-Agent", "Test");
            urlc.setRequestProperty("Connection", "close");
            urlc.setConnectTimeout(1500); 
            urlc.connect();
            return (urlc.getResponseCode() == 200);
        } catch (IOException e) {
            Log.e(LOG_TAG, "Error checking internet connection", e);
        }
    } else {
        Log.d(LOG_TAG, "No network available!");
    }
    return false;
}

so you should check first if you have an active connection , this method will ping google.com and check for internet connection, if is not reachable after 1.5 seconds it will return false

so you should do something like this (pseudocode)

if(hasActiveInternetConnection)
doyourfirebaseuploadstuff
else
spinner.dismiss()
Toast(please check your internet connection and try again)

Remember to add your internet permissions in your manifest

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

EDIT:

Another cool method and maybe more readable for someones can be this one

public boolean isInternetWorking() {
    boolean success = false;
    try {
        URL url = new URL("https://google.com");
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(10000);
        connection.connect();
        success = connection.getResponseCode() == 200;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return success;
}

it just works like the other one , instead that this will just wait for 10 seconds untill it returns the internet status

Gastón Saillén
  • 12,319
  • 5
  • 67
  • 77