BluetoothAdapter.getDefaultAdapter() throws RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()

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!

10 Replies to “BluetoothAdapter.getDefaultAdapter() throws RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()”

  1. 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

    1. Are you suggesting that every time before you call BluetoothAdapter.getDefaultAdapter(), you should call Looper.prepare()? That seems way more impractical to me given that we only need to initialize BluetoothAdapter once in the UI thread vs having to call Looper.prepare() every single time we call BluetoothAdapter.getDefaultAdapter()… or did I misunderstand what you’re saying.

      1. 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

        1. 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 call Looper.prepare();

          1. 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.

  2. 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

  3. 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

  4. 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

    1. 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 to BluetoothAdapter.getAdapter().

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.