12

When I'm trying to get default bluetooth adapter while i'm NOT in Activity, but in TimerTask (created inside Service) by using:

BluetoothAdapter.getDefaultAdapter();

I get the following exception:

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

My application do not have any activity - so is there any possibility to get this adapter away from Activity?

Elad Nava
  • 7,746
  • 2
  • 41
  • 61
Kocus
  • 1,613
  • 17
  • 31

5 Answers5

14

This appears to be a bug in Android and still exists in Android 4.0 (Ice Cream Sandwich)

To workaround this and be able to call BluetoothAdapter.getDefaultAdapter() from a worker thread (e.g. AsyncTask), all you have to do is call BluetoothAdapter.getDefaultAdapter() once on the main UI thread (e.g. inside the onCreate() of your current activity).

The RuntimeException is only thrown during initialization, and BluetoothAdapter.getDefaultAdapter() only initializes the first time you call it. Subsequent calls to it will succeed, even in background threads.

Toland Hon
  • 4,549
  • 2
  • 32
  • 36
6

Calling BluetoothAdapter.getDefaultAdapter() in the UI thread works, but is not very practical. I have tried the workaround with a fake Activity, but since I hate such workarounds, I decided to READ what the error message really says and it is nothing more than that the thread didn't call Looper.prepare().

So calling Looper.prepare() just before calling BluetoothAdapter.getDefaultAdapter() should solve the problem anywhere, not just in a UI thread.

Works fine for me so far.

Dhanuka
  • 2,826
  • 5
  • 27
  • 38
Martin Hoza
  • 157
  • 2
  • 10
  • That seems like a bad idea unless you actually intend your worker thread to be a Looper. – Brodo Fraggins Jun 30 '14 at 20:40
  • 1
    Note that you should check whether the current thread has already called `Looper.prepare()` like this: `if (Looper.myLooper() == null) { Looper.prepare(); }` Otherwise, you'll get a `RuntimeException` as this function may only be called once per thread. – Elad Nava Nov 09 '15 at 21:46
3

Not sure how correct it is, but I added this wrapper function:

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();
}

... and replaced all occurrences of BluetoothAdapter.getDefaultAdapter() with getDefaultBluetoothAdapter(). This works ok for me on: 2.2.1, 2.3.3, 4.0.4, 4.3

iforce2d
  • 8,194
  • 3
  • 29
  • 40
1

Beware of a gotcha that exists in 2.3.x, but which has been fixed in 4.x: if you call BluetoothAdapter.getDefaultAdapter() on any thread other than the main application thread, that thread must call Looper.prepare() and also subsequently Looper.loop().

Failing to do so will cause at least one problem that I ran into: accept() will succeed the first time you try to connect, but then not succeed on successive attempts, even after using close() on the ServerSocket.

This happens because in the older implementation of BluetoothAdapter, the cleanup of the SDP entry occurs by way of a message posted to a handler created on the thread where getDefaultAdapter() is called.

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
dfinn
  • 968
  • 1
  • 10
  • 16
0

Hi Kocus there is no any method called getDefault() in BluetoothAdapter calss . It should be BluetoothAdapter.getDefaultAdapter();

follow this link for more information.

vlio20
  • 8,955
  • 18
  • 95
  • 180
Sujit
  • 10,512
  • 9
  • 40
  • 45
  • 1
    Your example is for getting `BluetoothAdapter` from `Activity`. This is NOT what I want. – Kocus May 07 '11 at 11:12
  • yes but i think BluetoothAdapter.getDefaultAdapter() can't be called from the worker Thread . It should be from UI thread. – Sujit May 07 '11 at 11:24
  • 1
    Do not really understand what is fake Activity. Could you provide some code. – Ivan Jun 21 '12 at 12:18