应用退至后台时Cloud Firestore本地缓存数据回滚问题求助
游戏应用Firestore本地数据回滚问题排查求助
我开发了一款游戏应用,使用Cloud Firestore进行本地用户数据存储。数据持久化逻辑简单:用户操作数据时立即保存,任何Activity调用onPause()时也会保存数据。所有加载操作均使用Source.CACHE作为数据源,当前仅关注离线设备级数据持久化,不涉及云端同步。
经过6个月50名用户测试未出现问题,但开放Beta后部分用户反馈:应用通过设备“应用历史/后台按钮”退至后台再打开时,数据会回滚到旧状态;正常退出应用则无此问题。此问题并非遗漏保存导致的数据丢失,而是明确的回滚,业务逻辑中无回滚相关代码。
核心代码实现
加载方法
//I use this class to load a character public class CharacterLoader implements FetcherInterface { String documentId; //The document id of the character String accountId; //The account id of the user Source source = Source.CACHE; //Always, and always Source.CACHE. Never loading from the cloud. //My very simple constructor public CharacterLoader(String accountId, String documentId) { this.documentId = documentId; this.accountId = accountId; } //This method basically launch the loading procedure @Override public void go(DbResultListener dbResultListener) { FirebaseFirestore db = FirebaseFirestore.getInstance(); //Building the query to fetch the correct character by its documentId Query query = db.collectionGroup("localData").whereEqualTo("documentId", documentId); query.get(this.source).addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() { @Override public void onSuccess(QuerySnapshot queryDocumentSnapshots) { //If the loading was successful but there is no such character if (queryDocumentSnapshots.getDocuments().size() == 0) { dbResultListener.onError("Error - There was an error during loading the character. Please try again."); } else { //Loading was successful DocumentSnapshot documentSnapshot = queryDocumentSnapshots.getDocuments().get(0); Chara chara = documentSnapshot.toObject(Chara.class); if (chara == null) { //Character was null for some reason dbResultListener.onError("Error - Character not found!"); } else { //If the character found, I pass it to a listener callback so my app can use it dbResultListener.onSuccess(chara); } } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { //If ther was an error e.printStackTrace(); dbResultListener.onError("Error on character loading: "+e.getMessage()); } }); } }
保存方法
//I use this class to save character public class CharacterSaver implements FetcherInterface { Chara chara; //The data entity which we save String accountId; //User's account id String baseLink; //Link/path to my Cloud Firestore storage //A very simple constructor, it stops the app with a runtime error if the data parameter is null. public CharacterSaver(String baseLink, String accountId, Chara chara) { if (chara == null) { throw new RuntimeException("Chara object was null in parameter, cannot save!"); } this.accountId = accountId; this.chara = chara; this.baseLink = baseLink; } //This is my save method @Override public void go(DbResultListener dbResultListener) { FirebaseFirestore db = FirebaseFirestore.getInstance(); //Getting the document reference on the correct path with character's document id DocumentReference docRef = db.collection(baseLink).document(accountId).collection("localData").document(chara.getDocumentId()); docRef.set(chara).addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { //Saving was successful, noting to do. } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { e.printStackTrace(); //Passing the error with a listener to the application dbResultListener.onError("There was an error during saving character: " + e.getLocalizedMessage()); } }); } }
onPause()实现及静态角色实例
@Override protected void onPause() { super.onPause(); CharacterSaver saver = new CharacterSaver(Server.getUsersUrl(this), Identifiers.getAccountIdentifier(this), getChara()); saver.go(new DbResultListener() { @Override public void onError(String error) { DialogHelper.show(BaseActivity.this, error); } }); }
public static Chara getChara() { return charaPlayingStaticInstance; }
已尝试的排查措施
- 用Firebase Crashalytics全应用日志排查空指针、空数据状态
- 记录
onError()回调信息 - 记录角色版本号、保存/加载时间戳
- 保存后立即加载验证数据正确性
- 为
Chara类添加拷贝构造函数,避免引用传递问题 - 在线/离线环境下尝试复现问题
- 在多款设备及模拟器上尝试复现,均未成功
部分用户频繁出现此问题,而多数用户无此情况,现求助排查思路。
内容的提问来源于stack exchange,提问作者Adam Varhegyi
相关产品推荐
相关产品推荐

