使用AlertDialog保存数据时Android应用崩溃问题求助
解决saveData()中AlertDialog导致程序崩溃的问题
我在向数据库保存数据时,想用AlertDialog显示进度条,但调用saveData()方法完成数据保存后程序崩溃。以下是运行出错的saveData()方法代码:
private void saveData() { if (isPickPhoto) { StorageReference mRef = FirebaseStorage.getInstance().getReference().child("ShopList Images") .child(imgUri.getLastPathSegment()); AlertDialog.Builder builder = new AlertDialog.Builder(AddShopListActivity.this); builder.setCancelable(false); builder.setView(R.layout.progress_layout); AlertDialog dialog = builder.create(); dialog.show(); mRef.putFile(imgUri).addOnSuccessListener(taskSnapshot -> { Task<Uri> uriTask = taskSnapshot.getStorage().getDownloadUrl(); while (!uriTask.isComplete()) ; Uri urlImage = uriTask.getResult(); imageUrl = urlImage.toString(); uploadData(); dialog.dismiss(); }).addOnFailureListener(e -> { dialog.dismiss(); }); } else { Toast.makeText(this, "请从相册选择一张图片再上传", Toast.LENGTH_SHORT).show(); } }
而用于更新数据的updateData()方法却能正常运行,代码如下:
private void updateData() { AlertDialog.Builder builder = new AlertDialog.Builder(AddShopListActivity.this); builder.setCancelable(false); builder.setView(R.layout.progress_layout); AlertDialog dialog = builder.create(); dialog.show(); if (isPhotoChanged) { StorageReference storageReference = FirebaseStorage.getInstance().getReference().child("ShopList Images").child(imgUri.getLastPathSegment()); storageReference.putFile(imgUri).addOnSuccessListener(taskSnapshot -> { Task<Uri> uriTask = taskSnapshot.getStorage().getDownloadUrl(); while (!uriTask.isComplete()) ; Uri urlImage = uriTask.getResult(); imageUrl = urlImage.toString(); uploadData(); dialog.dismiss(); }).addOnFailureListener(e -> { Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); }); } else { imageUrl = oldImageUrl; uploadData(); dialog.dismiss(); } }
从LogCat的错误提示(java.lang.IllegalStateException: The specified child already exists)来看,崩溃核心不是AlertDialog,而是三个关键问题:
问题分析
- Firebase Database插入冲突:saveData是新增数据,但
uploadData()里可能手动指定了已存在的节点Key,Firebase默认不允许直接覆盖新增节点,触发了子节点已存在的异常;而updateData是更新已有数据,本身就是覆盖操作,所以不会触发这个错误。 - 主线程被阻塞:用
while (!uriTask.isComplete()) ;循环等待Uri,会卡死UI线程,不仅可能引发ANR,还会在Activity生命周期变化时(比如用户切后台)导致Dialog状态异常。 - Dialog Dismiss时机不安全:如果
uploadData()内部调用了finish()关闭Activity,后续执行dialog.dismiss()时,Activity已经销毁,会触发IllegalStateException。
解决步骤
1. 修复Firebase数据插入逻辑
如果是新增数据,不要手动指定Key,用push()生成唯一Key:
// 替换uploadData()里的新增逻辑 DatabaseReference shopListsRef = FirebaseDatabase.getInstance().getReference("shoplists"); // 自动生成唯一节点Key DatabaseReference newShopListRef = shopListsRef.push(); newShopListRef.setValue(yourShopListObject);
如果必须用自定义Key且允许覆盖,改用updateChildren():
Map<String, Object> updateMap = new HashMap<>(); updateMap.put(yourCustomKey, yourShopListObject); shopListsRef.updateChildren(updateMap);
2. 替换阻塞式Uri获取
把死循环等待改成异步监听,避免卡死主线程:
mRef.putFile(imgUri).addOnSuccessListener(taskSnapshot -> { taskSnapshot.getStorage().getDownloadUrl().addOnCompleteListener(uriTask -> { if (uriTask.isSuccessful()) { imageUrl = uriTask.getResult().toString(); uploadData(); safeDismissDialog(dialog); } else { safeDismissDialog(dialog); Toast.makeText(AddShopListActivity.this, "获取图片链接失败", Toast.LENGTH_SHORT).show(); } }); }).addOnFailureListener(e -> { safeDismissDialog(dialog); Toast.makeText(AddShopListActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); });
3. 安全关闭Dialog
封装一个方法,确保只有在Activity活跃且Dialog显示时才关闭:
private void safeDismissDialog(AlertDialog dialog) { if (!isFinishing() && !isDestroyed() && dialog != null && dialog.isShowing()) { dialog.dismiss(); } }
之后所有需要关闭Dialog的地方,都调用safeDismissDialog(dialog)代替直接dialog.dismiss()。
内容的提问来源于stack exchange,提问作者gkhnmr
相关产品推荐
相关产品推荐

