从Firebase实时数据库获取计数器值失败问题求助
问题分析与解决方案
你碰到的核心问题是Firebase Realtime Database的监听器是异步执行的,这也是新手用Firebase最容易踩的坑之一!
为什么原来的代码会崩溃?
addValueEventListener不会阻塞你的代码执行——当你调用它之后,程序会立刻继续往下执行data.setUser(...)、myRef.child(data.getId()).setValue(data)这些代码,但这时候onDataChange还没被触发,data.setId()根本没执行过,data.getId()自然是空的,调用child(null)肯定会崩溃。
为什么移进去后用户/密码为空?
如果把data.setUser(user.getText().toString())移到onDataChange里还是拿到null,大概率是你没有在回调内部重新获取EditText的内容(或者user/password不是EditText的正确引用)。另外,所有依赖计数器ID的操作都必须放在回调里,否则逻辑顺序完全不对。
修正后的代码
把所有需要用到计数器值的操作都放进onDataChange里面,同时确保在回调里获取最新的输入值:
invia.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { FirebaseDatabase database2 = FirebaseDatabase.getInstance(); final DatabaseReference myRef2 = database2.getReference("Counter/node"); // 用addListenerForSingleValueEvent只获取一次计数器值(比addValueEventListener更适合这个场景) myRef2.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // 1. 获取计数器并计算新ID,同时处理计数器不存在的初始情况 Counter counter = dataSnapshot.getValue(Counter.class); if (counter == null) { counter = new Counter(); counter.setCnt_android(0); } String newId = String.valueOf(counter.getCnt_android() + 1); // 2. 创建Data对象并设置所有属性(必须在回调内获取EditText最新输入值) Data data = new Data(); data.setId(newId); data.setUser(user.getText().toString()); data.setPassword(password.getText().toString()); // 3. 写入新数据到Information Android节点 FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference myRef = database.getReference("Information Android/"); myRef.child(newId).setValue(data); // 4. 更新计数器的值 counter.setCnt_android(Integer.parseInt(newId)); myRef2.setValue(counter); } @Override public void onCancelled(DatabaseError databaseError) { System.out.println("读取计数器失败: " + databaseError.getMessage()); } }); } });
额外优化建议
如果你的应用可能有多个用户同时新增数据,直接用setValue更新计数器会有并发冲突的风险——比如两个用户同时拿到同一个计数器值,最后只会保存一个。这种情况下推荐用Firebase事务来更新计数器,保证原子性:
myRef2.runTransaction(new Transaction.Handler() { @Override public Transaction.Result doTransaction(MutableData mutableData) { Counter counter = mutableData.getValue(Counter.class); if (counter == null) { counter = new Counter(); counter.setCnt_android(1); mutableData.setValue(counter); return Transaction.success(mutableData); } counter.setCnt_android(counter.getCnt_android() + 1); mutableData.setValue(counter); return Transaction.success(mutableData); } @Override public void onComplete(DatabaseError databaseError, boolean committed, DataSnapshot dataSnapshot) { if (committed) { // 事务成功,这里处理写入Data的逻辑 Counter updatedCounter = dataSnapshot.getValue(Counter.class); String newId = String.valueOf(updatedCounter.getCnt_android()); Data data = new Data(); data.setId(newId); data.setUser(user.getText().toString()); data.setPassword(password.getText().toString()); FirebaseDatabase.getInstance().getReference("Information Android/") .child(newId).setValue(data); } else { System.out.println("计数器更新失败: " + databaseError.getMessage()); } } });
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

