Android BluetoothAdapter.getDefaultAdapter()在不在活动中时引发RuntimeException

Android BluetoothAdapter.getDefaultAdapter()在不在活动中时引发RuntimeException,android,bluetooth,runtimeexception,Android,Bluetooth,Runtimeexception,当我尝试在未处于活动状态,但在TimerTask(在服务中创建)中获取默认蓝牙适配器时,请使用: BluetoothAdapter.getDefaultAdapter(); 我得到以下例外情况: Exception while invoking java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 我的应用程序没有任何活动-因此是否有可能将此适配器

当我尝试在未处于活动状态,但在
TimerTask
(在
服务
中创建)中获取默认蓝牙适配器时,请使用:

BluetoothAdapter.getDefaultAdapter();
我得到以下例外情况:

Exception while invoking java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

我的应用程序没有任何活动-因此是否有可能将此适配器从活动中移除?

嗨,Kocus在
BluetoothAdapter calss
中没有任何名为
getDefault()
的方法。 它应该是
BluetoothAdapter.getDefaultAdapter()


这似乎是安卓系统中的一个缺陷,安卓4.0(冰淇淋三明治)中仍然存在这一缺陷

要解决此问题并能够从工作线程(例如AsyncTask)调用
BluetoothAdapter.getDefaultAdapter()
,您只需在主UI线程上调用
BluetoothAdapter.getDefaultAdapter()


RuntimeException仅在初始化期间引发,并且
BluetoothAdapter.getDefaultAdapter()
仅在您第一次调用它时初始化。对它的后续调用将成功,即使在后台线程中也是如此。

UI
线程中调用
BluetoothAdapter.getDefaultAdapter()
可以工作,但不太实用。我用一个假的活动尝试了这种变通方法,但由于我讨厌这种变通方法,我决定阅读错误消息的真正含义,只不过线程没有调用
Looper.prepare()

因此,在调用
BluetoothAdapter.getDefaultAdapter()
之前调用
Looper.prepare()
应该可以在任何地方解决问题,而不仅仅是在UI线程中


到目前为止,对我来说效果很好。

注意2.3.x中存在的问题,但在4.x中已经解决了:如果在主应用程序线程以外的任何线程上调用
BluetoothAdapter.getDefaultAdapter()
,则该线程必须调用
Looper.prepare()
,随后还必须调用
Looper.loop()

如果不这样做,至少会导致我遇到一个问题:
accept()
将在您第一次尝试连接时成功,但即使在ServerSocket上使用
close()
后,连续尝试也不会成功


这是因为在BluetoothAdapter的旧实现中,SDP条目的清理是通过向调用
getDefaultAdapter()
的线程上创建的处理程序发送消息来进行的。

不确定它是否正确,但我添加了此包装函数:

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

您的示例是从
活动中获取
BluetoothAdapter
。这不是我想要的。是的,但我认为无法从工作线程调用BluetoothAdapter.getDefaultAdapter()。它应该来自UI线程。不真正理解什么是假活动。你能提供一些代码吗?这似乎是个坏主意,除非你真的打算让你的工作线程成为一个循环器。请注意,你应该检查当前线程是否已经像这样调用了
Looper.prepare()
if(Looper.myLooper()==null){Looper.prepare();}
否则,您将得到一个
运行时异常
,因为每个线程只能调用一次此函数。bug页面上有任何链接吗?请参阅Android对此bug的响应: