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

向ArrayAdapter添加对象时应用崩溃,蓝牙设备ListView展示故障

蓝牙设备列表ArrayAdapter崩溃问题排查与解决

嘿,我之前做蓝牙设备扫描的学校项目时,也碰到过一模一样的情况——只要碰ArrayAdapter应用就崩!后来排查下来都是一些容易踩的Android UI开发坑,给你梳理下可能的原因和对应的解决办法:

最常见的崩溃原因

  • 子线程直接操作UI:蓝牙扫描的回调(不管是经典蓝牙还是BLE扫描)都是在子线程跑的,Android规定所有UI相关操作(包括更新ArrayAdapter、刷新ListView)必须在主线程执行,直接在子线程修改Adapter必崩。
  • Adapter初始化不规范:比如用了getApplicationContext()而不是当前Activity实例当Context,或者绑定的数据源(比如ArrayList)是null就创建Adapter,又或者还没拿到ListView实例就绑定Adapter了。
  • 数据源修改后未通知Adapter:虽然这个不一定会崩溃,但如果是在错误线程里修改数据源再调用notifyDataSetChanged(),也会触发崩溃。

一步步排查修复

1. 强制在主线程更新Adapter

把蓝牙扫描回调里的设备名称添加逻辑,用runOnUiThread()包裹起来,切换到主线程操作:

// 蓝牙扫描回调中拿到设备信息后
final String deviceName = device.getName() != null ? device.getName() : "未知设备";
runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // 往数据源里加设备名
        yourDeviceList.add(deviceName);
        // 通知Adapter更新UI
        yourArrayAdapter.notifyDataSetChanged();
    }
});

2. 检查Adapter初始化是否正确

确保初始化时用对Context、数据源非空,并且先拿到ListView再绑定Adapter:

// 正确的初始化流程
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_layout);

    // 1. 先初始化数据源(必须非null)
    ArrayList<String> deviceNames = new ArrayList<>();
    // 2. 拿到ListView实例
    ListView deviceListView = findViewById(R.id.list_view_device);
    // 3. 创建Adapter,用当前Activity作为Context
    ArrayAdapter<String> adapter = new ArrayAdapter<>(this, 
            android.R.layout.simple_list_item_1, deviceNames);
    // 4. 绑定Adapter到ListView
    deviceListView.setAdapter(adapter);
}

千万别用getApplicationContext()当Adapter的Context,这会导致布局加载异常!

3. 查看崩溃日志精准定位

打开Android Studio的Logcat,搜索AndroidRuntime,找到崩溃的堆栈信息:

  • 如果是CalledFromWrongThreadException:就是线程问题,按步骤1解决。
  • 如果是NullPointerException:检查是不是ListView、Adapter或者数据源没初始化就用了。

完整简化测试代码

给你一个能跑的简化版代码,你可以对照着改自己的项目:

package z.ut010;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import java.util.ArrayList;

public class BluetoothDeviceActivity extends AppCompatActivity {

    private ArrayList<String> deviceList;
    private ArrayAdapter<String> adapter;
    private BluetoothAdapter bluetoothAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化ListView和Adapter
        ListView listView = findViewById(R.id.list_view);
        deviceList = new ArrayList<>();
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, deviceList);
        listView.setAdapter(adapter);

        // 初始化蓝牙适配器
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            // 设备不支持蓝牙,提示用户
            return;
        }

        // 请求开启蓝牙
        if (!bluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, 1);
        } else {
            startBluetoothScan();
        }
    }

    private void startBluetoothScan() {
        // 开始BLE扫描(经典蓝牙用startDiscovery(),回调逻辑类似)
        bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                final String deviceName = device.getName() != null ? device.getName() : "未知设备";
                // 切换到主线程更新UI
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // 避免重复添加同一设备
                        if (!deviceList.contains(deviceName)) {
                            deviceList.add(deviceName);
                            adapter.notifyDataSetChanged();
                        }
                    }
                });
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1 && resultCode == RESULT_OK) {
            // 用户开启蓝牙后开始扫描
            startBluetoothScan();
        }
    }
}

别忘了在AndroidManifest.xml里加必要权限:

<!-- 蓝牙基础权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 6.0+ 需要位置权限才能扫描蓝牙 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

内容的提问来源于stack exchange,提问作者Zacord

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:34:25