BroadcastReceiver lifecycle - android

1) I have an Activity. This Activity starts a service, which in turn creates and registers a BroadcastReceiver.
2) I have an Activity. This Activity creates and registers a BroadcastReceiver.
When does BroadcastReceiver's life end in each of the above cases? In other words - when it gets destroyed and won't listen to broadcasts anymore?

Declare broadcast receiver in manifest to achieve independent life cycle for it.
http://developer.android.com/reference/android/content/BroadcastReceiver.html

Only onReceive() method is called in BroadcastReciver's life cycle.

A BroadcastReciever life cycle ends (ie stop receiving broadcast) when you unregister it. usually you would do this in the onPause/onStop method. but it's up to you technically.
Example:
#Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));
}
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}

Related

service does not listen to certain broadcasts

My service:
#Override
public void onCreate() {
if (debug_mode) {Log.i(TAG,"onCreate");}
super.onCreate();
// set receivers
m_filter.addAction("PREPARE_AUDIO");
m_receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (debug_mode) {Log.i(TAG,"broadcast received: " + intent.getAction());}
if (intent.getAction().equals("PREPARE_AUDIO")) {
set_up_audio();
}
}
};
registerReceiver(m_receiver, m_filter);
}
and my activity:
#Override
protected void onStart() {
super.onCreate(savedInstanceState);
if (debug_mode) Log.i(TAG, "onCreate");
setContentView(R.layout.activity_guide);
// start service
startService(new Intent(this, PlayerService.class));
}
#Override
protected void onStart() {
if (debug_mode) {Log.i(TAG,"onStart");}
super.onStart();
// prepare audio
Intent intent = new Intent();
intent.setAction("PREPARE_AUDIO");
sendBroadcast(intent);
}
This won't trigger the BroadcastReceiver in my service. It won't trigger it either if I put the code on onCreate or onResume. It will trigger it, however, if put e.g. on some Listener associated with a Button, or in the activity's onStop callback. Why is that?
Rather than try to send a broadcast right away, just have the service do its setup work in its onCreate() or onStartCommand() method.
Note that using system broadcasts for this is a fairly bad idea, unless your service is in a separate process from your UI. Even then, you need to think through the security, as any app can tell your service what to do, by sending it broadcasts.
If your service and UI will be in the same process, use an in-process event bus (e.g., LocalBroadcastManager, greenrobot's EventBus), not only for improved security, but for better performance.

Dynamic BroadcastReceivers: LocalBroadcastManager.registerReceiver vs registerReceiver

I'm trying to receive broadcasts from a service with 2 different receivers. One receiver update's a view so I register it in the activity's onResume method.
When the app is not in the foreground I use the other receiver so I can show a system notification when the background service completes.
The code below is how I'm registering my receivers:
#Override
protected void onPause() {
// unregister local
unregisterReceiver(localReceiver);
// register remote
registerReceiver(remoteReceiver, filter);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
// remove remote receiver
// since remote is only registered in onPause it won't be registered during the first onResume call
// so we want to ignore any exceptions
try {
unregisterReceiver(remoteReceiver);
} catch (IllegalArgumentException e) {
Log.e(LOG_TAG, "No receiver registered, could be first time");
}
// add local receiver
registerReceiver(localReceiver, filter);
Log.i(LOG_TAG, "resumed. should be registered");
}
The two receiver's are instantiated like this at the top of the Activity class:
BroadcastReceiver localReceiver = new BroadcastReceiver() { ... };
WaitTimeReceiver remoteReceiver = new WaitTimeReceiver();
The Service makes the intent as:
broadcastIntent = new Intent(Support.SERVICE_BR);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
// later on sends using
sendBroadcast(broadcastIntent);
The Filter in the Activity is made to match:
filter.addAction(Support.SERVICE_BR);
filter.addCategory(Intent.CATEGORY_DEFAULT);
Everything above is working the pause resume functionality works as expected, but my question is why the LocalBroadcastManager was not?
Using LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this) and then calling lbm.registerReceiver(localReceiver) was not receiving any of my broadcasts for either.
Why wasn't the LocalBroadcastManager receiving any of my broadcasts?
BroadcastReceivers registered with LocalBroadcastManager can only receive broadcasts sent with LocalBroadcastManager. Broadcasts sent with an Activity's or Service's sendBroadcast() method cannot be received by LocalBroadcastManager Receivers.
Use the LocalBroadcastManager#sendBroadcast() method instead. For example:
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)

onReceive called many times

I have a service that get data from an other application.
When I get date I send message to broadCast in order to refresh the UI.
The onReceive method is called many times and data displayed multiple times.
this is my code:
DataService.java
if(sizeLat == 1) {
sendMessage("Alerte1;");
}
else {
sendMessage("Alerte2;");
}
private void sendMessage(String message) {
Log.w("","==> send message");
Intent intent = new Intent("my-event");
// add data
intent.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
MainActivity.java
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("","Onreceiver");
String message = intent.getStringExtra("message");
if(message.equals("Alerte1")){
parentItems.add(message);
adapter.notifyDataSetChanged();
}}};
#Override
protected void onResume() {
Log.d(TAG, "On Resume");
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}
How can I resolve the problem ?
Put broadcast register line in onCreate and unregister it in onDestroy() method. The line which you have to move from onResume() to onCreate is:-
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}
Possibly, you have two instances of the activity living at the same time. Make a breakpoint on the message receiver and check the address of the instance of your activity class and see if they are different each time the onReceive is called.
There are a few reasons why you could have two instances living at the same time, but one of the most common is leaking context within the activity.
More on this topic.
I fixed same problem by unregister BroadcastReceiver in onPause method
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver,new IntentFilter("my-event")));
Register it in OnResume Method
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}

Working with BroadcastReceiver

I have defined a BroadcastReceiver in my activity in the following way to get results from an IntentService running on another thread:
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
boolean isSyncCompleted = intent.getBooleanExtra("issynccompleted", false);
if (isSyncCompleted){
showAlert("Sync completed in service");
}
context.unregisterReceiver(receiver);
}
};
//register receiver for service
registerReceiver(receiver, new IntentFilter(ContentSyncService.SERVICE_INTENT_FILTER));
Note that I am unregistering my receiver in the onReceive code block and not in onPause. That is because I want to have the receiver listening even when the activity has been destroyed.
But I keep getting the error: "Activity ... has leaked IntentReceiver ... that was originally registered here. Are you missing a call to unregisterReceiver()?"
This solution works for me, I override the Activity methods, not a BrodcastReceiver:
#Override
protected void onPause() {
super.onPause();
// unregister receiver
LocalBroadcastManager.getInstance(this).unregisterReceiver(
mMessageReceiver);
}
#Override
protected void onResume() {
super.onResume();
// register receiver
LocalBroadcastManager.getInstance(this).registerReceiver(
mMessageReceiver, new IntentFilter("your.package.name"));
}
Only will unregister receiver if you receive action at least one time.
So you need unregister your receiver in OnPause (and in other place if you need), because there you are safe that always will unregister the receiver.
Intead of use context.unregisterReceiver(receiver) inside your receiver,
Try it:
activity.unregisterReceiver(this);

Update the UI of the calling activity or start a new activity when the alarm is triggered from a broadcast receiver

I am writing an alarm code and using a broadcast receiver. I am able to receive the broadcast receiver. but now I want to come back to the calling activity and update the UI of my activity. I am not able to this.
I used the following code in my activity but it is never executing that code.
private BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "I am back!!", Toast.LENGTH_LONG).show();
}
};
#Override
protected void onPause()
{
super.onPause();
unregisterReceiver(myBroadcastReceiver);
}
#Override
protected void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter("com.test.Main");
registerReceiver(myBroadcastReceiver, intentFilter);
}
in the manifest file I have included the following, here gotAlarm is the broadcast receiver file
<receiver android:name=".gotAlarm"
android:enabled="true">
</receiver>
gotAlarm file is one which gets called from the pending intent of the alarm set
public class gotAlarm extends BroadcastReceiver {
public void onReceive(Context context, Intent intent){
Toast.makeText(context, "Wake Up!!", Toast.LENGTH_LONG).show();
}
}
May be I am missing something very basic.
please help.
Two things:
If you dynamically register the receiver via Context.registerReceiver() then you won't receive broadcasts when Activity is paused (or stopped or not-running). If you need to receive broadcasts even when Activity is paused then create a top-level BroadcastReceiver class (as opposed to your inner class) and use <receiver> to register it.
BroadcastReceiver lifecycle docs state that BroadcastReceiver object is alive only during processing of onReceive(). You can not do any async tasks like showing dialogs, etc.. In your case (Activities might not be running and you receive a broadcast) you should use NotificationManager to notify user something happened.
I have dropped this way and I am starting a new activity on receiving broadcast. And I am sending information data from calling activity to broadcast and from broadcast to next activity. This has served the purpose.
Did you register your BroadcastReceiver (you can do this in the 'onResume'-method of your Activity)? Also, you should unregister your BroadcastReceiver in the 'onPause'-method.

Categories

Resources