So I’m using some hardware SDK that attempts to scan for bluetooth devices on Android and hit into this exception below when calling: BluetoothAdapter.getDefaultAdapter()
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.bluetooth.BluetoothAdapter$1.<init>(BluetoothAdapter.java:984)
at android.bluetooth.BluetoothAdapter.<init>(BluetoothAdapter.java:984)
at android.bluetooth.BluetoothAdapter.getDefaultAdapter(BluetoothAdapter.java:329)
After researching this problem, it turns out there’s a bug in Android (which apparently still exists in Android 4.0: Ice Cream Sandwich according to the discussions I’ve been reading). The bug is during the initialization of the default adapter, there exists UI code which means it needs to be ran on the UI thread.
Update 2013/04/22: Martin has brought to my attention that as long as you call BluetoothAdapter.getDefaultAdapter()
inside any thread that has already called Looper.prepare()
, it should work. It doesn’t have to be the UI thread.
I was attempting to use AsyncTask
to search for bluetooth devices in the background. Workaround suggest running the code in the main thread or using Handler
so that code is queued in the main thread. Unfortunately both solutions block the UI thread and what you see is a progress dialog with a spinner that stops spinning.
It turns out however if you call BluetoothAdapter.getDefaultAdapter()
in the main UI thread, calling it subsequently no longer crashes, even in background threads.
Hope that helps!
Hi,
calling BluetoothAdapter.getDefaultAdapter() in the UI thread works, but is not very practical. Actually, I think, it works just because the UI thread calls Looper.prepare() by default.
So calling Looper.prepare() just before calling BluetoothAdapter.getDefaultAdapter() will solve the problem anywhere, not just in a UI thread. Works fine for me.
greetings
Are you suggesting that every time before you call
BluetoothAdapter.getDefaultAdapter()
, you should callLooper.prepare()
? That seems way more impractical to me given that we only need to initializeBluetoothAdapter
once in the UI thread vs having to callLooper.prepare()
every single time we callBluetoothAdapter.getDefaultAdapter()
… or did I misunderstand what you’re saying.Yes, calling looper.prepare() every time would be the most ugly solution. But it seems to be enough to call getDefaultAdapter() once – for the first time in a thread that has called Looper.prepare(). And you do not always have a UI Thread (starting a service in a BOOT_COMPLETED receiver was my case)
So one (not so ugly) solution could be to create a special thread for it only for the first time. That thread wouldn’t do anything else than:
Looper.prepare();
BluetoothAdapter.getDefaultAdapter();
There is always a point (may be more, but not a lot), where the application starts and that is the place where I would put the “LooperBluetoothAdapterInitializingThread”.
I am not saying, that this is the only/best solution, it just works for me so far. But if there is a better way to do this, I would like to know it too.
Greetings
Martin
If you’re going to go and create a special thread just to initialize
BluetoothAdapter.getDefaultAdapter();
, is it really that different than initializing it on the UI thread.I understand in the event your object doesn’t have access to the UI thread, your solution is a better workaround. But if you’re already inside an Activity or Application, why not take advantage that the looper has already been prepared?
In other words, if you’re going to spawn a new thread when the Application first starts up, why not just call
BluetoothAdapter.getDefaultAdapter();
where you’re about to spawn that new thread and initialize BluetoothAdapter in the UI thread instead. Therefore you won’t have to spawn any new thread nor callLooper.prepare();
Yes, you are right, if you already have a UI thread or any other thread, that has called Looper.prepare(), you can use it. I just wanted to clarify, that it does not have to be exactly an UI thread.
Ah. Gotcha.
Hi, Martin.
I’m having the same problem. I follow your suggestion, but it does not work for me.
Please, may you give a example?
Thanks
Hi HelderSi,
if you are having exactly the same problem as I did, the following two lines of code should help:
Looper.prepare();
BluetoothAdapter.getDefaultAdapter();
– meaning that (only the first time) before you call BluetoothAdapter.getDefaultAdapter() you must call Looper.prepare(). I think, it does not matter, how you do this.
– Either calling getDefaultAdapter() in the UI thread, because the UI thread calls Looper.prepare() after it starts automatically, so you do not have to do it any more
– or create a separate thread to do nothing else but call Looper.prepare() and getDefaultAdapter() and then finish.
The easiest way to test this is to put Looper.prepare() just before your getDefaultAdapter() call. If this does not work, I am afraid, I can not help 🙁
But I hope I could help 🙂
Martin
Hi,
I am having the same problem for devices of API Level 18.
Even if I put Looper.prepare() before the BluetoothAdapter.getAdapter(), I get the error saying
W/System.err: java.lang.RuntimeException: Unable to start receiver sos.android.blesos.receivers.ScanReceiver: java.lang.RuntimeException: Only one Looper may be created per thread
which means there is a Looper already started.
But without the Looper.prepare() statement, I get the
W/BluetoothAdapter Unhandled exception: Runtime Exception can’t create handler inside thread that has not called looper.prepare() android
I haven’t touched this code in a while, but my guess is that you’re calling
Looper.prepare()
multiple times in the same thread.My suggestion here would be for you to only call
Looper.prepare()
once, remember that you called it, and don’t call it on subsequent calls toBluetoothAdapter.getAdapter()
.