11

I had to implement a feature to this app which consists of an Activity and a Service working on the background (it implements Service, not IntentService).

I went through a few tutorials on the Internet that are supposed to work, and they all use LocalBroadcastManager, which by the way is the recommended by Android:

If you don't need to send broadcasts across applications, consider using this class with LocalBroadcastManager instead of the more general facilities described below.

I literally lost a day to find out the problem why it wouldn't work for me: it only works if I use Context.sendBroadcast(). and Context.registerReceiver() instead of the LocalBroadcastManager methods.

Now my app is working, but I feel I am going against the best practices, and I don't know why. Any ideas why it could be happening?

EDIT:

After I wrote this question I went further on the problem. LocalBroadcastManager works through a Singleton, as we should call LocalBroadcastManager.getInstance(this).method(). I logged both instances (in the Activity and in the Service) and they have different memory addresses. Now I came to another question, shouldn't a Service have the same Context as the Activity that called it? From this article a Service runs on the Main Thread, hence I'd think the Context would be the same.

Any thoughts on that? (sorry for the long post)

Code samples:

MyService

public class MyService extends Service {

...

// When an event is triggered, sends a broadcast

Intent myIntent = new Intent(MainActivity.MY_INTENT);
myIntent.putExtra("myMsg","msg");
sendBroadcast(myIntent);

// Previously I was trying:
// LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(myIntent);

}

MyActivity

public class MainActivity {

...

private BroadcastReceiver messageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) { 
            Log.d("onReceive", "received!");
            // TODO something
        }
    };

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(messageReceiver, new IntentFilter(MY_INTENT));
    // Previously I was trying:
    // LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(messageReceiver, new IntentFilter(MY_INTENT));
}
}
AJ D
  • 52
  • 1
  • 6
Teo Inke
  • 5,928
  • 4
  • 38
  • 37

3 Answers3

15

I've never used LocalBroadcastManager, but it sounds like you have to register your receiver on there (i.e. lbm.registerReceiver(...), not mycontext.registerReceiver(...)). Are you doing that?

Now I came to another question, shouldn't a Service have the same Context as the Activity that called it? From this article a Service runs on the Main Thread, hence I'd think the Context would be the same.

The Context class is not related to threads. In fact, both Service and Activity are (indirect) subclasses of Context -- so they're their own Contexts!
That's why you can use "this" as a Context.

But regardless of which context you send into LocalBroadcastManager.getInstance(), you should be getting the exact same LBM instance out. I can't think of any reason that you wouldn't -- except if you're running the Activity and Service in different processes?

Snild Dolkow
  • 6,669
  • 3
  • 20
  • 32
  • That was my ultimately question: seems like they are in different process. I started my Service from the MainActivity with startService(serviceIntent) – Teo Inke Apr 20 '15 at 20:05
  • 1
    And you don't have any [android:process](http://developer.android.com/guide/topics/manifest/service-element.html#proc) attribute set on the activity or service? – Snild Dolkow Apr 20 '15 at 20:11
  • Yes, the project did have android:process=":remote" for the service in the Manifest, and I didn't notice. This was the reason for the whole problem then. Thanks! – Teo Inke Apr 22 '15 at 14:29
12

Declaration:

private BroadcastReceiver receiver;

Initialization:

receiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        //todo
    }
};

Registration:

LocalBroadcastManager.getInstance(context).registerReceiver(receiver, new IntentFilter("RECEIVER_FILTER"));

context can be any type of Context, you can use the application context.

Unregister:

LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);

Broadcast:

Intent intent = new Intent("RECEIVER_FILTER");
intent.putExtra("EXTRA", someExtra);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
smb
  • 834
  • 1
  • 8
  • 17
  • I did pretty much the same, but the two LocalBroadcastManager.getInstance(context) are getting a different reference – Teo Inke Apr 20 '15 at 19:59
  • Hm. Then I don't know the reason. I checked the source code of `LocalBroadcastManager` and it works from the main thread (there is used a `Handler`, which is created as `new Handler(context.getApplicationContext().getMainLooper())`). – smb Apr 20 '15 at 20:05
  • 1
    I even called lbm.getInstance() changing `this` to `getMyApplicationContext()` in both places, still gets a different reference. Weird – Teo Inke Apr 20 '15 at 20:09
  • Its an old answer, but worked just perfectly for me on API 28. I am using location service and trying to send lat and lon from the service back the activity. But I was not registering localbroadcast correctly. – zeeshan Apr 08 '19 at 21:39
  • 1
    I had mistake in this part LocalBroadcastManager.getInstance(context).sendBroadcast(intent); – Ayman Al-Absi Jun 21 '19 at 22:33
7

check out if your Service and Activity are run in different process, LocalBroadcastManager can't apply in different process.(you should see it in AndroidManifest.xml file)

Michael
  • 646
  • 6
  • 16
  • What is meant by different process? What is a process here? – sofs1 Sep 07 '16 at 11:26
  • as for the meaning of process I suggest you search it by google, then keep this in your mind: by default, an app has only one process in name of it's package name, but developer could add process in manifest, like let a service run in different process by add a tag like this:android:process="" after service name, so if you can find the keyword "process=" in manifest file and after "=" follows a differentNameWithPackageName, then you could know it's a multi-process app. – Michael Sep 08 '16 at 07:46
  • GOt it. Could you answer this question http://stackoverflow.com/questions/39343099/why-intent-sent-by-localbroadcastmanager-from-intentservice-is-not-received-by-b Please, I am struck for almost a week. – sofs1 Sep 10 '16 at 22:12