将扫描文本写入Firebase实时数据库时遇空指针异常求助
问题:Firebase实时数据库写入时触发空指针异常
我开发了一个Android OCR项目,支持拍照/从相册选图,通过裁剪库提取目标区域后识别文本,识别结果能正常显示,但无法写入Firebase Realtime Database。数据库连接已配置成功,问题出在getTextFromImage方法的数据库写入环节。
相关代码(MainActivity.java)
package com.example.myapplication; import android.Manifest; import android.annotation.SuppressLint; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.util.SparseArray; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.android.gms.vision.Frame; import com.google.android.gms.vision.text.TextBlock; import com.google.android.gms.vision.text.TextRecognizer; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.auth.OAuthCredential; import com.google.firebase.auth.OAuthProvider; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.theartofdev.edmodo.cropper.CropImage; import com.theartofdev.edmodo.cropper.CropImageView; private void getTextFromImage(Bitmap bitmap) { TextRecognizer recognizer = new TextRecognizer.Builder(this).build(); if (!recognizer.isOperational()) { Toast.makeText(MainActivity.this, "Error Occurred!!", Toast.LENGTH_SHORT).show(); } else { Frame frame = new Frame.Builder().setBitmap(bitmap).build(); SparseArray<TextBlock> textBlockSparseArray = recognizer.detect(frame); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < textBlockSparseArray.size(); i++) { textBlock = textBlockSparseArray.valueAt(i); stringBuilder.append(textBlock.getValue()); stringBuilder.append("\n"); } textView_data.setText(stringBuilder.toString()); FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser(); String uid = textBlock.getValue(); System.out.println("okutulan yazı 2: "+uid); ReadWriteUserDetails writeUserDetails = new ReadWriteUserDetails(uid); DatabaseReference referenceProfile = FirebaseDatabase.getInstance().getReference("Cropped all texts"); if (firebaseUser != null) { referenceProfile = referenceProfile.child(firebaseUser.getUid()); } System.out.println("hata verdi 2"); referenceProfile.child(firebaseUser.getUid()).setValue(writeUserDetails).addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { Toast.makeText(MainActivity.this, "Data is written on the database successfully", Toast.LENGTH_LONG).show(); } }); button_capture.setText("Retake"); button_copy.setVisibility(View.VISIBLE); } } }
控制台报错信息
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.myapplication, PID: 28303 java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=203, result=-1, data=Intent { launchParam=MultiScreenLaunchParams { mDisplayId=0 mBaseDisplayId=0 mFlags=0 }(has extras) }} to activity {com.example.myapplication/com.example.myapplication.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.google.firebase.auth.FirebaseUser.getUid()' on a null object reference at android.app.ActivityThread.deliverResults(ActivityThread.java:4520) at android.app.ActivityThread.handleSendResult(ActivityThread.java:4563) at android.app.ActivityThread.-wrap22(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1698) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6776) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.google.firebase.auth.FirebaseUser.getUid()' on a null object reference at com.example.myapplication.MainActivity.getTextFromImage(MainActivity.java:144) at com.example.myapplication.MainActivity.onActivityResult(MainActivity.java:104) at android.app.Activity.dispatchActivityResult(Activity.java:7280) at android.app.ActivityThread.deliverResults(ActivityThread.java:4516) at android.app.ActivityThread.handleSendResult(ActivityThread.java:4563) at android.app.ActivityThread.-wrap22(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1698) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6776) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
解决方案
问题分析
- 空指针直接原因:代码仅在
referenceProfile赋值时检查firebaseUser != null,但后续调用referenceProfile.child(firebaseUser.getUid())未判空,用户未登录时firebaseUser为null,触发空指针。 - 额外问题:
- 循环结束后
textBlock可能指向最后一个TextBlock,若识别结果为空会导致uid赋值出错 - 数据库节点路径重复添加用户UID,导致层级错误
- 循环结束后
修复代码
private void getTextFromImage(Bitmap bitmap) { TextRecognizer recognizer = new TextRecognizer.Builder(this).build(); if (!recognizer.isOperational()) { Toast.makeText(MainActivity.this, "Error Occurred!!", Toast.LENGTH_SHORT).show(); return; } Frame frame = new Frame.Builder().setBitmap(bitmap).build(); SparseArray<TextBlock> textBlockSparseArray = recognizer.detect(frame); StringBuilder stringBuilder = new StringBuilder(); String recognizedText = ""; for (int i = 0; i < textBlockSparseArray.size(); i++) { TextBlock textBlock = textBlockSparseArray.valueAt(i); stringBuilder.append(textBlock.getValue()); stringBuilder.append("\n"); } recognizedText = stringBuilder.toString(); textView_data.setText(recognizedText); // 先检查用户是否登录 FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser(); if (firebaseUser == null) { Toast.makeText(MainActivity.this, "请先登录账号", Toast.LENGTH_SHORT).show(); button_capture.setText("Retake"); button_copy.setVisibility(View.VISIBLE); return; } ReadWriteUserDetails writeUserDetails = new ReadWriteUserDetails(recognizedText); DatabaseReference referenceProfile = FirebaseDatabase.getInstance().getReference("Cropped all texts"); // 节点路径修正:直接使用用户UID作为子节点,避免重复添加 referenceProfile.child(firebaseUser.getUid()).setValue(writeUserDetails) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { Toast.makeText(MainActivity.this, "数据已成功写入数据库", Toast.LENGTH_LONG).show(); } else { Toast.makeText(MainActivity.this, "数据写入失败:" + task.getException().getMessage(), Toast.LENGTH_LONG).show(); } } }); button_capture.setText("Retake"); button_copy.setVisibility(View.VISIBLE); }
关键修复点
- 提前检查
firebaseUser是否为null,未登录时提示并终止后续操作 - 用
recognizedText变量存储完整识别结果,避免依赖循环后的textBlock对象 - 修正数据库节点路径,避免重复添加用户UID
- 在
onComplete中判断任务是否成功,添加失败提示
内容的提问来源于stack exchange,提问作者smooth
相关产品推荐
相关产品推荐

