2

I have a service running in which I am getting location updates. The service returns the location successfully. But after that I am trying to broadcast the location to any activity that might be listening. I have registered the receiver in my activity but for some reason the onReceive method is not being called. Here is the code inside my onLocationChanged method inside my service.

@Override
public void onLocationChanged(Location location) {
    Intent intent = new Intent();
    intent.setAction("LocationBroadcast");
    double lat = location.getLatitude();
    double lng = location.getLongitude();
    intent.putExtra("lat", lat);
    intent.putExtra("lng", lng);
    //I am initializing the broadcaster object in onCreate method of my service but I am putting it here for simplicity
    broadcaster = LocalBroadcastManager.getInstance(this);
    //This Toast successfully shows my coordinates so I know the problem is not with this method
    Toast.makeText(GoogleFusedLocationApiService.this, ""+lat+", "+lng+"", Toast.LENGTH_SHORT).show();
    broadcaster.sendBroadcast(intent);
}

Inside my activity in my onCreate method, I am registering for the LocationBroadcast like so.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    ...
    IntentFilter intentFilter = new IntentFilter("LocationBroadcast");
    super.registerReceiver(mMessageReceiver, intentFilter);
    startService(new Intent(MyApp.getAppContext(), GoogleFusedLocationApiService.class));
}

I've tried this.registerReceiver(mMessageReceiver, intentFilter); and LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, intentFilter); but neither worked.

Here is my mMessageReceiver defined,

public BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        double lat = intent.getDoubleExtra("lat", 0);
        double lng = intent.getDoubleExtra("lng", 0);
        // This Toast never shows and neither can I debug this method at all
        // so for now the only conclusion is the broadcast is not being received
        Toast.makeText(MyApp.getAppContext(), "Cordinates are "+lat+", "+lng+"", Toast.LENGTH_SHORT).show();
    }
};

Moreover, some of the details that I might think matter after some research. I haven't declared receiver in the manifest because I read that you only do that when you want your application to launch when the broadcast is received but I only want my application to react when it is already running. Not launch whenever the services sends a broadcast.

And I haven't extended the activity to BroadcastReceiver either since the activity is already extended to FragmentActivity

The app does not crash and onLocationChanged is located inside the service that is being started after the BroadcastReceiver is registered so onLocationChanged is not invoked before the BroadcastReceiver has been registered

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Rehan Yousaf
  • 735
  • 2
  • 7
  • 20
  • Where exactly is the receiver located ? In the same same activity as the `onlocationChanged` or the other activities ? – Santanu Sur Dec 30 '17 at 13:30
  • `onLocationChanged` is located in a separate service. Receiver is located inside the activity that for example will be on view at the time of the broadcast. – Rehan Yousaf Dec 30 '17 at 13:35
  • why are you calling super.registerReceiver? – JoxTraex Dec 30 '17 at 13:50
  • Well, to register my BroadcastReceiver to listen to that specific broadcast that my Service is sending. – Rehan Yousaf Dec 30 '17 at 13:51
  • Another thing to check is if you read the documentation @ https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html have you tried registering with the LocalBroadcastManager's registerReceiver as opposed to the Activity method? I believe .registerReceiver vs .registerReceiver may be different. Being that you are dispatching a local broadcast, it may be that you're not dispatching to your actual receiver. I'm pretty confident that this is the problem. If this works let me know and i'll post this as an answer. – JoxTraex Dec 30 '17 at 14:00
  • Yeah, I'm sure. I completely removed the unregister method to remove that doubt. Still doesn't work. – Rehan Yousaf Dec 30 '17 at 14:00
  • `LocalBroadcastManager.getInstance(this).registerReceiver((mMessageReceiver),new IntentFilter("LocationBroadcast"));` also doesn't work. I had already checked that but I just checked it again. – Rehan Yousaf Dec 30 '17 at 14:17
  • Another dumb question did you ensure (with logs) that you are actually calling the registerReceiver? Put a log ontop of the registerReceiver and on bottom to confirm that it's registered. – JoxTraex Dec 30 '17 at 14:19
  • I've resolved the issue and posted it as an answer. Thanks for the help – Rehan Yousaf Dec 31 '17 at 20:34

1 Answers1

1

I managed to solve the issue. I will post my findings and the answer for anyone else faced with this issue in the future. I have probably dumbed down a lot of concepts here but for the purpose of understanding this specific problem I'll try to be accurate to the best of my understanding.

The Answer:

The problem was that I was not sending the Broadcast and receiving the broadcast with the same Context. What I mean by that is, this is how I had declared my service in the Manifest file

<service
        android:name=".GoogleFusedLocationApiService"
        android:process=":google_fused_location_api_service"/>

The android:process attribute meant that this service would run on a different process from the process that the app is running on. So when I was calling, super.registerReceiver(mMessageReceiver, intentFilter); it was being called from the context of the Activity and when I was calling broadcaster = LocalBroadcastManager.getInstance(this); broadcaster.sendBroadcast(intent); here sendBroadcast is being called from the context of the service which has a different process running for it. So you see I was registering the receiver from a different context and sending broadcast from a different context.

LocalBroadcastManager only works when the broadcast is being sent and received from the same process i.e., context. So in this case, since my service and my app/activity are running or separate processes i.e., contexts I cannot use LocalBroadcastManager. I need to use the Global broadcasts and make sure that I am registering the broadcast and sending the broadcast from the same context.

Now since the I have a static context of the app that I can use anywhere by simply calling, MyApp.getAppContext() which you can learn how to do from this answer now if I register the broadcast receiver and send broadcasts using this context, that means both are done from the same context which is MyApp.getAppContext() and now I begin to receive broadcasts successfully.

So to sum it up, if you have separate process for your service, use MyApp.getAppContext().registerReceiver() and MyApp.getAppContext().sendBroadcast()

If you have the same process for your service or don't have the android:process attribute in your service tag in Manifest file, then you can use LocalBroadcastManager.getInstance(this).registerReceiver() and LocalBroadcastManager.getInstance(this).sendBroadcast().

You can still use MyApp.getAppContext here but using LocalBroadcastManager is the best practice and the proper way of doing things in the second case.

Rehan Yousaf
  • 735
  • 2
  • 7
  • 20