简体   繁体   中英

Firebase persisted write failing after being offline

I have an Android application that uses Firebase as backend. Now that Firebase has support for local persistence I decided to get rid of my own local storage solution and use the built-in instead.

Everything is working, except for one thing. Making changes while being offline, closing the app, connect, and start the app.

The code that I use to update my data on the server is something like this:

public void saveDataToServer(String id, Boolean isHandled) {
    Firebase firebase = new Firebase("https://example.firebaseio.com/item_data/items/1234/data").child(id);
    if(firebase == null)
        return;

    firebase.authWithCustomToken(mToken, mAuthResultHandler);

    Map<String, Object> children = new HashMap<>();
    children.put("updated_at", FireBaseHelper.getFormattedTimestamp());
    children.put("is_handled", isHandled);
    firebase.updateChildren(children);
}

mMainFirebaseInstance is some Firebase object that is on the root level of where this data is saved. And this all runs in a Service that is connected to my Activities/Fragments

Sidenote: I get the authentication token mToken from some REST API that someone else made for me to use.

When I am connected, have the app connected and make changes: everything works

When I am not connected, open the app, make changes, close the app, open the app and connect: everything works

When I am not connected, open the app, make changes, close the app, connect and open the app: The following error is logged:

06-22 17:51:52.343 28073-28395/? W/RepoOperation﹕ Persisted write at /item_data/items/7454/data/7454141033945571998119 failed: FirebaseError: Invalid token in path

I've searched in Firebase's documentation and can't figure out where the problem is. I would say that this has something to do with the authentication, but I don't know anymore where to look.

So my question is: What is the problem here? What am I doing wrong?

EDIT:

The FireBaseHelper looks like this:

class FireBaseHelper {
    public static Firebase getItemsBase(String itemId) {
        Firebase fb = new Firebase(Constants.FIREBASE_URL + "item_data/items/" + itemId + "/data");
        return fb;
    }

    public static String getFormattedTimestamp() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
        return simpleDateFormat.format(Calendar.getInstance().getTime());
    }
}

It can create the main Firebase instance and return a timestamp in a specific format. Constants.FIREBASE_URL is just https://example.firebaseio.com/

EDIT2:

mMainFirebaseInstance = FireBaseHelper.getItemsBase("1234");

which would be replaceable by

mMainFirebaseInstance = new Firebase("https://example.firebaseio.com/item_data/items/1234/data");

A possible timestamp is:

2015-06-22 23:12:24

The id that is used in the saveDataToServer is retrieved from a snapshot that is given to me in a ValueEventListener. For example:

ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            HashMap data = dataSnapshot.getValue(HashMap.class);
            Set keySet = data.keySet();
            String id = keySet.get(0);
        }
        ...
}

EDIT3:

Android: 5.0
Firebase: 2.3.0+
Java: 7

This turned out to be a bug in the Firebase Android SDK. It has been fixed in version 2.3.1 that was just released. See https://www.firebase.com/docs/android/changelog.html

I can reproduce the behavior you're seeing with this Activity.onCreate :

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Firebase.setAndroidContext(this);
    Firebase.getDefaultConfig().setPersistenceEnabled(true);
    Firebase.getDefaultConfig().setLogLevel(Logger.Level.DEBUG);
    Firebase ref = new Firebase("https://stackoverflow.firebaseio.com/30987733");
    Map<String, Object> children = new HashMap<>();
    children.put("updated_at", new Date().toString());
    children.put("is_handled", true);
    ref.updateChildren(children);
}

The steps to reproduce that go with the above code:

  1. Go into airplane mode
  2. Start the app (so that it calls updateChildren
  3. Kill the app
  4. Go online
  5. Start the app

In my tests, the second update does get written to Firebase. But there is a warning written in the Android logs:

W/RepoOperation﹕ Persisted write at /30987733 failed: FirebaseError: Invalid token in path

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM