BluetoothAdapter.getDefaultAdapter() бросает RuntimeException, а не в действие
Когда я пытаюсь получить адаптер bluetooth по умолчанию, пока я НЕ в действии, но в TimerTask
(создан внутри Service
), используя:
BluetoothAdapter.getDefaultAdapter();
Я получаю следующее исключение:
Exception while invoking java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
У моего приложения нет активности - так есть ли возможность отключить этот адаптер от Activity?
Ответы
Ответ 1
Это, кажется, ошибка в Android и все еще существует в Android 4.0 (Ice Cream Sandwich)
Чтобы обойти это и иметь возможность вызывать BluetoothAdapter.getDefaultAdapter()
из рабочего потока (например, AsyncTask), вам нужно только вызвать BluetoothAdapter.getDefaultAdapter()
один раз в основном потоке пользовательского интерфейса (например, внутри onCreate()
вашей текущей активности).
RuntimeException генерируется только при инициализации, а BluetoothAdapter.getDefaultAdapter()
инициализирует только первый раз, когда вы его вызываете. Последующие вызовы будут успешными даже в фоновом потоке.
Ответ 2
Вызов BluetoothAdapter.getDefaultAdapter()
в потоке UI
работает, но не очень практичен. Я пробовал обходной путь с поддельной Activity, но, так как я ненавижу такие обходные пути, я решил прочитать, что сообщение об ошибке действительно говорит, и это не что иное, как поток не вызывал Looper.prepare()
.
Поэтому вызов Looper.prepare()
непосредственно перед вызовом BluetoothAdapter.getDefaultAdapter()
должен решить проблему в любом месте, а не только в потоке пользовательского интерфейса.
Прекрасно работает для меня.
Ответ 3
Не знаю, насколько это правильно, но я добавил эту функцию обертки:
static boolean m_calledLooperAlready = false;
BluetoothAdapter getDefaultBluetoothAdapter() {
if ( !m_calledLooperAlready ) {
try {
android.os.Looper.prepare();
} catch ( RuntimeException e ) { e.printStackTrace(); }
m_calledLooperAlready = true;
}
return BluetoothAdapter.getDefaultAdapter();
}
... и заменил все вхождения BluetoothAdapter.getDefaultAdapter()
на getDefaultBluetoothAdapter()
. Это работает нормально для меня: 2.2.1, 2.3.3, 4.0.4, 4.3
Ответ 4
Остерегайтесь gotcha, который существует в 2.3.x, но который был исправлен в 4.x: если вы вызываете BluetoothAdapter.getDefaultAdapter()
в любом потоке, отличном от основного потока приложения, этот поток должен вызывать Looper.prepare()
, а затем Looper.loop()
.
В противном случае будет возникать хотя бы одна проблема, с которой я столкнулся: accept()
будет успешным при первом попытке подключения, но затем не будет успешным при последовательных попытках даже после использования close()
в ServerSocket.
Это происходит потому, что в старой версии BluetoothAdapter очистка записи SDP происходит путем сообщения, отправленного в обработчик, созданный в потоке, где вызывается getDefaultAdapter()
.
Ответ 5
Привет Kocus, в BluetoothAdapter calss
нет никакого метода, называемого getDefault()
.
Это должно быть BluetoothAdapter.getDefaultAdapter();
перейдите по этой ссылке для получения более подробной информации.