You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:29:09