Android跨类获取labelString值时空指针异常致应用崩溃排查
崩溃根因
报错的空指针不是textMe字段为空,是你在CameraActivity中使用的tracker实例本身没有初始化,为null值。你在onCreate生命周期阶段直接访问tracker.textMe时,Tracker对象还未完成创建,自然会抛出空对象引用异常。
除此之外你的代码还有两个逻辑bug会导致后续就算不崩溃也拿不到正确值:
textMe字段是在Tracker执行识别框绘制逻辑时才会赋值的,Activity刚启动onCreate阶段,目标检测逻辑还没开始运行,就算tracker实例不为空,这个字段也没有有效值- 你在TTS初始化的位置就提前把
speak变量赋值为当时的tracker.textMe,后续就算Tracker更新了识别结果,定时任务里读的永远是最开始拿到的旧空值,拿不到最新的labelString
修复方案
1. 优先初始化tracker实例
确保在访问tracker的任何属性之前,已经完成了Tracker对象的实例化,把初始化逻辑放到onCreate中所有访问tracker的代码之前:
// 先在CameraActivity类的成员位置声明tracker private Tracker tracker; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); // 先初始化tracker,替换成你项目中实际的Tracker构造方法和参数 tracker = new Tracker(/* 传入你项目要求的构造参数,比如上下文、资源等 */); // 再往下写TTS、相机相关的原有逻辑 // ... }
2. 动态取值加空判断,不要提前固定值
删掉onCreate里一开始写的String speak = tracker.textMe;,改成每次定时任务执行时再读取最新的识别结果,同时加多层空判断,从根源避免空指针:
mTTS = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() { @Override public void onInit(int status) { if(status == TextToSpeech.SUCCESS) { mTTS.setLanguage(Locale.ENGLISH); runnable = new Runnable() { @Override public void run() { handler.postDelayed(this, 1000L); String speak = ""; // 逐层判空 if (tracker != null && !TextUtils.isEmpty(tracker.textMe)) { speak = tracker.textMe; Toast.makeText(CameraActivity.this, speak, Toast.LENGTH_SHORT).show(); mTTS.speak(speak, TextToSpeech.QUEUE_FLUSH, null); } } }; handler.post(runnable); // 删掉你原来重复写的第二遍handler.post(runnable); 否则会启动两个重复的定时任务 } else { Toast.makeText(CameraActivity.this, "Error", Toast.LENGTH_SHORT).show(); } } });
3. 修正Tracker类的textMe字段声明
在Tracker类的成员变量位置声明textMe,给默认初始值,加volatile保证多线程读取的可见性,避免字段未初始化、多线程值不同步的问题:
// Tracker类成员位置添加 public volatile String textMe = "";
如果你的识别逻辑存在trackedObjects为空、循环不执行的场景,可以根据业务需求决定是清空textMe还是保留上一次识别结果,避免读到过期值。
额外说明
日志末尾的A resource failed to call close警告属于资源未释放问题,和本次空指针崩溃无关,后续可以排查下相机流、文件流、TTS资源的关闭逻辑即可。
内容的提问来源于stack exchange,提问作者Jericho
相关产品推荐
相关产品推荐

