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?


person Kocus    schedule 07.05.2011    source источник
comment
См. ответ Android на эту ошибку: code.google.com/p/android. /issues/detail?id=16587   -  person Jojo56400    schedule 25.05.2016


Ответы (5)


Похоже, это ошибка в Android, и она все еще существует в Android 4.0 (Ice Cream Sandwich).

Чтобы обойти это и иметь возможность вызывать BluetoothAdapter.getDefaultAdapter() из рабочего потока (например, AsyncTask), все, что вам нужно сделать, это вызвать BluetoothAdapter.getDefaultAdapter() один раз в основном потоке пользовательского интерфейса (например, внутри onCreate() вашей текущей активности).

Исключение RuntimeException возникает только во время инициализации, а BluetoothAdapter.getDefaultAdapter() инициализируется только при первом вызове. Последующие вызовы к нему будут успешными даже в фоновых потоках.

person Toland Hon    schedule 23.02.2013
comment
Любые ссылки на странице ошибки? - person Denis Gladkiy; 11.04.2015

Вызов BluetoothAdapter.getDefaultAdapter() в потоке UI работает, но не очень практичен. Я попробовал обходной путь с поддельной активностью, но, поскольку я ненавижу такие обходные пути, я решил ПРОЧИТАТЬ, что на самом деле говорит сообщение об ошибке, и это не что иное, как то, что поток не вызывал Looper.prepare().

Таким образом, вызов Looper.prepare() непосредственно перед вызовом BluetoothAdapter.getDefaultAdapter() должен решить проблему где угодно, а не только в потоке пользовательского интерфейса.

У меня пока работает нормально.

person Martin Hoza    schedule 21.04.2013
comment
Это кажется плохой идеей, если вы на самом деле не хотите, чтобы ваш рабочий поток был Looper. - person Brodo Fraggins; 01.07.2014
comment
Обратите внимание, что вы должны проверить, вызывал ли уже текущий поток Looper.prepare() следующим образом: if (Looper.myLooper() == null) { Looper.prepare(); } В противном случае вы получите RuntimeException, так как эта функция может быть вызвана только один раз для каждого потока. - person Elad Nava; 10.11.2015

Не уверен, насколько это правильно, но я добавил эту функцию-оболочку:

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

person iforce2d    schedule 30.10.2013

Остерегайтесь подводного камня, существующего в версии 2.3.x, но исправленного в версии 4.x: если вы вызываете BluetoothAdapter.getDefaultAdapter() в любом потоке, отличном от основного потока приложения, этот поток должен вызывать Looper.prepare(), а затем Looper.loop().

Невыполнение этого требования вызовет по крайней мере одну проблему, с которой я столкнулся: accept() будет успешным при первой попытке подключения, но затем не удастся при последовательных попытках, даже после использования close() на ServerSocket.

Это происходит потому, что в более старой реализации BluetoothAdapter очистка записи SDP происходит посредством сообщения, отправленного обработчику, созданному в потоке, где вызывается getDefaultAdapter().

person dfinn    schedule 02.10.2013

Привет, Кокус, нет никакого метода с именем getDefault() в BluetoothAdapter calss. Должно быть BluetoothAdapter.getDefaultAdapter();

для получения дополнительной информации перейдите по этой ссылке.

person Sujit    schedule 07.05.2011
comment
Ваш пример предназначен для получения BluetoothAdapter из Activity. Это НЕ то, чего я хочу. - person Kocus; 07.05.2011
comment
да, но я думаю, что BluetoothAdapter.getDefaultAdapter() нельзя вызывать из рабочего потока. Это должно быть из потока пользовательского интерфейса. - person Sujit; 07.05.2011
comment
Не очень понимаю, что такое фейковая активность. Не могли бы вы предоставить код. - person Ivan; 21.06.2012