4

As the title says, is there a way to run BroadcastReceiver onReceive() method asynchronously?

Based on its implementation, android runs the onReceive() method on the main thread.

I am using the BroadcastReceiver to explicitly request permission to communicate with a USB device. When the request permission dialog box has received permission, the onReceive() method is called, but since it runs on the main thread, there is no way (at least, not that I know of) to signal when it is complete. Polling on a boolean flag would block the main thread, which in turn would block the onReceive() method from being called.

Is there a way to async call the onReceive() or is there an alternative way to explicitly (without using intent filters in the manifest) request permission and connect to a USB device?

Edit: I would like it such that the method blocks until permission is acquired and connection is established.

Geo P
  • 754
  • 1
  • 5
  • 18

3 Answers3

3

You can have a partial async behavior of what you wished.

Starting with Honeycomb, you can call goAsync(), and then you have 10 seconds or so to do your work asynchronously .

Example of usage can be shown here.

Community
  • 1
  • 1
android developer
  • 114,585
  • 152
  • 739
  • 1,270
1

You can send a broadcast in onReceive of your broadcast receiver. The broadcast intent can be registered in Activity's lifecycle methods and can be unregistered in the same.

Nitin Sethi
  • 1,416
  • 1
  • 11
  • 19
  • Yes that is a solution, but (see edit) I would like to block until I have permission. – Geo P Oct 02 '13 at 15:14
  • "When the request permission dialog box has received permission, the onReceive() method is called". Isn't that your receiver receives the broadcast when the permission has been granted? – Nitin Sethi Oct 02 '13 at 15:15
  • Yes that is correct, when permission is acquired, the `UsbManager` broadcasts the `PendingIndent` and the receiver calls the `onReceive()` and checks the intent extras. But this runs on the main thread. – Geo P Oct 02 '13 at 15:19
  • you can always start a new thread in onReceive method and return immediately. – Nitin Sethi Oct 02 '13 at 15:23
  • But during synchronization (using a Semaphore) the main thread will block and the `onReceive()` would never get called. – Geo P Oct 02 '13 at 15:29
  • You can disable/enable your Receiver programmatically using PackageManager's method setComponentEnabledSetting(..). – Nitin Sethi Oct 02 '13 at 15:36
1

First of all, you shouldn't do anything that blocks on the main thread. Second, unless you use registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) you should never do anything that takes much time in BroadcastReceiver.onReceive since it will most likely be killed after 10 seconds (see the documentation for BroadcastReceiver). You should start an AsyncTask or a separate thread from the onReceive method. If you want to stop interaction with the rest of the UI until the USB device is connected, do so without blocking the main thread. Explicitly disable things or switch to some simple Fragment or Activity with a loading GIF or anything besides blocking. Blocking on the main thread will cause the wait-or-kill system dialog to pop up, and no user ever selects wait.

The simple answer to your question is to register the receiver programmatically using registerReceiver instead of using the manifest, but I had to provide some disclaimers first.

Dave
  • 4,282
  • 2
  • 19
  • 24