Android Studio中Firestore Timestamp空指针异常问题(跨Activity场景)
嘿,我来帮你搞定这个空指针问题!从你的代码和异常信息来看,问题出在两个关键地方,我给你一步步拆解并提供解决方案:
问题原因分析
这个空指针是因为你调用timestamp.toDate()时,timestamp对象是null,背后的诱因有两个:
- 提交逻辑的异步顺序错误:你点击提交按钮后立刻调用了
startActivity(intent)跳转回ListView,但Firestore的set()写入操作是异步执行的——APP跳转时,新建议的文档可能还没被Firestore服务器完全写入,尤其是createdAt用的是FieldValue.serverTimestamp(),这个值是服务器端生成的,客户端刚发起写入时拿到的临时快照里,这个字段是null,此时ListView的实时监听到不完整的文档,就会触发空指针。 - 缺少Null安全判断:你没有对
createdAt字段做任何非空校验,哪怕是旧文档出现数据缺失的情况,也会直接崩溃。
解决方案
1. 修正提交页面的跳转时机
把跳转代码移到Firestore写入成功的回调里,确保数据完全同步到服务器后再回到ListView:
send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { v.getId(); String title = art1.getText().toString(); String content = art2.getText().toString(); Intent intent = new Intent(create_announce_main.this, SuggestionMain.class); Map<String, Object> suggest = new HashMap<>(); suggest.put("title", title); suggest.put("content", content); suggest.put("name", name); suggest.put("recID", recID); suggest.put("admin_name", ""); suggest.put("response_content", ""); suggest.put("response_status", "未回覆"); suggest.put("response_time",FieldValue.serverTimestamp()); suggest.put("createdAt", FieldValue.serverTimestamp()); firebaseFirestore.collection("Suggestion").document().set(suggest).addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { Toast.makeText(create_announce_main.this, "added succesfully", Toast.LENGTH_LONG).show(); // 写入成功后再跳转,确保数据完整 startActivity(intent); // 关闭当前页面,避免返回时重复提交 finish(); } else { // 处理写入失败的场景,给用户提示 Toast.makeText(create_announce_main.this, "提交失败,请重试", Toast.LENGTH_LONG).show(); } } }); // 移除原来的startActivity,不要提前跳转 } });
2. 在ListView页面添加Null安全校验
即使遇到文档未完全同步或数据缺失的情况,也能避免崩溃,同时给用户合理的提示:
DocumentReference docRef = firebaseFirestore.collection("users").document(userID); docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() { @Override public void onComplete(@NonNull Task<DocumentSnapshot> task) { if (task.isSuccessful()) { DocumentSnapshot document = task.getResult(); if (document.exists()) { Log.d("TAG", "DocumentSnapshot data: " + document.getData()); recID = document.getString("recID"); firebaseFirestore.collection("Suggestion") .whereEqualTo("recID",recID) .orderBy("createdAt", Query.Direction.DESCENDING) .addSnapshotListener((documentSnapshots, error) -> { // 先处理监听错误 if (error != null) { Log.e("TAG", "监听Suggestion集合出错", error); return; } // 校验快照是否为空 if (documentSnapshots == null) { Log.w("TAG", "未获取到Suggestion数据"); return; } ar.clear(); for (DocumentSnapshot snapshot : documentSnapshots){ idlv = snapshot.getId(); // 安全处理createdAt字段 String date2 = "未知时间"; Object createdAtObj = snapshot.getData().get("createdAt"); if (createdAtObj instanceof Timestamp) { Timestamp timestamp = (Timestamp) createdAtObj; Date date = timestamp.toDate(); date2 = date.toString(); } // 其他字段也做非空兜底 String adminName = snapshot.getString("admin_name") != null ? snapshot.getString("admin_name") : "無"; String responseStatus = snapshot.getString("response_status") != null ? snapshot.getString("response_status") : "未回覆"; ar.add(new itemAnnounce(R.drawable.notes, snapshot.getString("title"), "回饋於 "+date2, "回覆管理者:"+ adminName, "回覆狀態:"+ responseStatus, idlv, url)); } // 优化:可以把adapter作为成员变量,避免每次重新创建 adapterAnnounce adapterAnnounce = new adapterAnnounce(getApplicationContext(), R.layout.list_row_announce, ar); lv1.setAdapter(adapterAnnounce); lv1.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Object selectedObj =adapterAnnounce.getItem(position).getId(); String obj = selectedObj.toString(); Intent i = new Intent(SuggestionMain.this, announce_Page.class); i.putExtra("annId",obj); startActivity(i); } }); }); } else { Log.d("TAG", "No such document"); } } else { Log.d("TAG", "get failed with ", task.getException()); } } });
另外还有个小优化:你每次监听触发都重新创建Adapter,其实可以把Adapter设为Activity的成员变量,初始化一次后,每次清空数据直接调用adapter.notifyDataSetChanged(),这样性能会更好。
内容的提问来源于stack exchange,提问作者neko12
相关产品推荐
相关产品推荐

