如何避免Android应用处理错误时崩溃?附OnClickListener代码示例
针对你的Android蓝牙场景的崩溃预防方案
嘿,结合你的代码场景,我整理了几个实用的崩溃预防点,一步步帮你避免应用崩溃:
1. 扩大异常捕获范围,不要只抓IOException
你现在在onClick里只捕获了IOException,但sendData方法里可能还会抛出其他异常(比如NullPointerException——如果outputStream未初始化、IllegalStateException等等)。只抓特定异常会导致其他未预期的异常直接引发崩溃。
建议调整捕获逻辑,先抓具体异常,再兜底捕获通用Exception,同时不要只打印堆栈,给用户友好的提示,也方便自己排查问题:
b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (on) { try { sendData("b"); // 可选:添加发送成功的提示 } catch (IOException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "发送数据失败:蓝牙连接异常", Toast.LENGTH_SHORT).show(); } catch (NullPointerException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "发送失败:蓝牙未初始化完成", Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "发送失败:未知错误", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(getApplicationContext(), "You should turn bluetooth on!", Toast.LENGTH_SHORT).show(); } } });
2. 提前校验关键对象,从源头避免空指针
你的sendData方法里直接使用outputStream,如果这个流未初始化或者已经关闭,会直接抛出NPE。建议在方法开头先做有效性校验:
public void sendData(String s) throws IOException { // 先校验outputStream是否有效 if (outputStream == null) { throw new IOException("输出流未初始化或已关闭"); } try { byte[] byteString = s.getBytes(); outputStream.write(byteString); outputStream.flush(); // 记得flush确保数据发送完成 } catch (IOException e) { // 这里可以做一些流的回收操作,比如关闭重连 throw e; // 抛出去让上层处理 } }
3. 不要在UI线程执行蓝牙IO操作
蓝牙数据发送属于耗时IO操作,直接在onClick(UI线程)执行的话,不仅可能触发ANR(应用无响应),还可能因为线程阻塞引发其他异常。建议把sendData放到子线程执行,比如用Thread实现:
b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (on) { new Thread(new Runnable() { @Override public void run() { try { sendData("b"); // 发送成功后回到UI线程提示 runOnUiThread(() -> Toast.makeText(getApplicationContext(), "发送成功", Toast.LENGTH_SHORT).show()); } catch (IOException e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(getApplicationContext(), "发送失败:蓝牙连接异常", Toast.LENGTH_SHORT).show()); } catch (Exception e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(getApplicationContext(), "发送失败:未知错误", Toast.LENGTH_SHORT).show()); } } }).start(); } else { Toast.makeText(getApplicationContext(), "You should turn bluetooth on!", Toast.LENGTH_SHORT).show(); } } });
4. 全局异常兜底(终极防线)
即使做了局部捕获,还是可能有遗漏的未处理异常,建议设置全局异常捕获器,避免应用直接崩溃,同时记录日志方便后续排查:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { // 这里可以把异常日志写入本地文件或者上报到服务器 Log.e("GlobalCrash", "未捕获异常:", throwable); // 可选:弹出提示后重启应用或者回到主页面 Toast.makeText(getApplicationContext(), "抱歉,应用出现问题,即将重启", Toast.LENGTH_LONG).show(); // 重启应用示例 Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); android.os.Process.killProcess(android.os.Process.myPid()); }); } }
记得在AndroidManifest.xml里把application的name设置为这个自定义类。
内容的提问来源于stack exchange,提问作者Takichiii
相关产品推荐
相关产品推荐

