Home > Electronics > Android Intents, registerReceiver, BroadcastReceiver, updating GUI elements from threads

Android Intents, registerReceiver, BroadcastReceiver, updating GUI elements from threads

August 12th, 2011

First, let me make one thing clear.  I have Java.  I think that there is something wrong with the way people who code java think.  It’s like they have to make things as complicated as possible, as verbose as possible, and as convoluted as possible for no reason.

I had a simple goal, and that was to have a background thread receive some data and update a text field in an “Activity”.  There were plenty of webpages that attempted to describe how to do it, referring to explicit intents, to modifying the Manifest.xml file, and all sorts of other jargon – but no clear examples.  I came across dozens of posts from people trying to do the same thing I wanted to do, but no answers.  I spent about 4 hours trying to piece together a method that worked. 

Hopefully, this simple explanation will help someone..

If you want to send data from one thread to another you can do it through a messaging protocol, and encapsulate data in that message if needed.  One big complication is that the messaging can occur across applications, it can be directed at a specific target if you know it exists, or it can be ambiguous and you figure something will deal with it.  The messages can also invoke an application (“Activity”) to do something.

What I’m going to describe is how to send a message from one part of an application to another – with the typical goal being to send data to the active “activity” to display data or somesuch.

 

1. In the activity where you want to receive messages, you need to create a class within the activity class (I have no idea what the java developers were smoking to come with this idea) that extends BroadcastReceiver().  You then want to override onReceive() to contain the business logic.

 

public class ActivityClass extends Activity {

  private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals("net.reza.SET_BATT")) {
            setBattery(intent.getIntExtra("value", 0));
        }        
    }
  };

  /* rest of your code */

}

In this example, I’m creating  mReceiver which is a BroadcastReceiver but I am modifying the onReceive() method.  In the method, I’m checking to see if the activity string is equal to “net.reza.SET_BATT”.  This can be anything.  There are some standards that are meaningless.  Use whatever you want.  I think it’s called an intent or intent-filter.  I’m going to call it a ‘tag’ for clarity.

2. You need to register that mReceiver is capable of handing the “net.reza.SET_BATT” tag.  There are a bunch of places to do this in your code.  I stuck it in the onCreate() method for the Activity class.

 

@Override

public void onCreate(Bundle savedInstanceState) {
  IntentFilter ifilt = new IntentFilter("net.reza.SET_BATT");
  registerReceiver(mReceiver, ifilt);

  /* more code */

 

A lot of the documentation said you need to modify the Manifest.xml file and stick it in there, but that was a mess and not obvious how to make it work.  Defining it this way is /much/ easier, and in my mind, much more manageable.  Why do java people love XML so much? 

And I have no idea why they call these tags “intent-filters” but they do.  Based on my code, you don’t need to bother with the action.equals() line, as the only time it will be called is if that tag is registered with registerReceiver(), and I’ve only registered that one tag.   But if you register multiple tags with the same BroadcastReceiver then you should check to see which one is being called.

 

3. You need to invoke that tag.  This can be done anywhere, as far as I know.  Even from another application.  In my case, it’s from a background thread that monitors the battery voltage by polling a device over bluetooth. 

public class BatteryMonitor extends Thread{

Context context;

public BatteryMonitor(Context y) {

  this.context = y;

}

 

public void run() {

  /* some code */

  Intent i = new Intent("net.reza.SET_BATT");
  i.putExtra("value", bat);
  this.context.sendBroadcast(i);

  /* more code */

}

 

Couple things here.  First, I still have no clue what a context is, who owns it, and how to use it properly.   I kept trying different things till it worked.  I passed the output of getBaseContext() to the constructor of the background thread, and that seemed to work.  I think some other options are getContext() and getApplicationContext(), so try those too.  Please post a comment if you know what’s going on.  

So we create an Intent with the same tag.  We can then stick extra data in there – in my case, I add an int. And then you call the sendBroadcast() method from the context object to make it go. 

 

I now need to go write some more code in C to cleanse my mind from all this gibberish…

Electronics

  1. | #1

    THANK YOU! A real, full, java example! And they said there was no such thing. I’ve been a C# programmer for years and I can’t believe how I’ve struggled to write this stoopid droid app.

  1. No trackbacks yet.