Android: Does BroadcastManager have queues? - android

I have a simple BroadcastReceiver that I setup in my onResume method of my Activity.
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mNotificationReceiver, new IntentFilter(QuickstartPreferences.NEW_NOTIFICATION));
}
I unregister the receiver on onPause:
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mNotificationReceiver);
}
I have a background service that sends the broadcast message to this:
Intent newNotification = new Intent(QuickstartPreferences.NEW_NOTIFICATION);
newNotification.putExtra("title", data.getString("title"));
LocalBroadcastManager.getInstance(this).sendBroadcast(newNotification);
My question is, if the background service broadcasts a message when the Activity is not opened and now when the Activity is resumed, will it be able to pick up the broadcasted messages? If no, how to maintain a queue to store broadcasted messages when Activity is not open?

LocalBroadcast is queued but not persisted. In your activity onPause() you unregistered receiver so you can not receive further broadcast. the sendBroadcast() will check receiver, if there is no reciever it will return false to indicate failure.
If you want always get notification, try to register broadcast at application level rather than activity level.

if the activity is not running then it'll never receive it. what you can do is:
check if your activity is running before/after you send the broadcast, if its not running then you could store a sharedPreference flag that tells your activity when it runs again to do whatever task that it has to do when it receives that broadcast.

Related

Update UI at onResume using LocalBroadcastManager

I have a Service that frequently updates the Main Activity UI by passing values via a LocalBroadCastManager. The following method is triggered within the Service to pass the value to the Main Activity:
private void updateUI(String statusValue){
broadcastIntent.putExtra("status", statusValue);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
}
Within the Main Activity I added a BroadcastReceiver to pick up the value and update the UI accordingly:
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String brStatus = intent.getStringExtra("status");
if(brStatus != null){
//Update UI
}
}
}
};
When the user navigates to another activity the receiver for the Broadcasts is unregistered as the user wont see the UI. Then onResume() when the user returns to the activity the receiver is reregistered:
LocalBroadcastManager.getInstance(this)
.registerReceiver(mMessageReceiver, new IntentFilter("speed-stats"));
UPDATE:
Whilst the activity is paused, the user can make actions (such as 'Pause') by clicking on Pending Intents on the ongoing notification. This action is handled within onStartCommand() of the Service:
case PAUSE_SERVICE :
Log.i(LOG_TAG, "Pause Foreground service.");
startForeground(NOTIF_ID,makeNotification(isRunning = false));
updateUI("paused");
stopSpeed();
break;
This works fine, however i have noticed that the UI is not updated as the receiver is unregistered whilst the activity is paused.
Is it possible to continue these UI updates despite pausing? Or is it possible to apply the UI updates as soon as the activity is resumed?
When the user navigates to another activity the receiver for the
Broadcasts is unregistered as the user wont see the UI.
This is the reason why your Activity's data is not up to date. Since the broadcast receiver is unregistered, data sent by the service won't be received.
Since its not a great idea keep the receiver registered, one solution would be:
Bind the service in on onResume() an unBind() it in onStop().
Inside service maintain data object, which will hold the latest data.
After service is binded, call the service method through Binder which
will return the the data Object with latest data.
Update the data in your Activity accordingly.
You can refer this SO for binding/unbinding service

How can a background service know if activity is killed or not

I have an activity that starts a background service. Once it is started, it runs forever.
Lets say the background service needs the activity that started it to update something. Then how can I start the activity again "If it is not started" however if it is already started then send a broadcast?
Thanks
You would have to bind to the service in your activity. Then, in the service, implement the onBind and onUnbind methods to set a boolean "bound". Check the boolean to see whether the activity is active.
With activity you mean the service's process. If the service is started forever, then its process its started foerever (except when the system kill its for recovering memory purpose and recreates it later). That doesnt mean the rest of activities/fragments/services are not kill. A service is just an entry point for your application and it gives your process a position into the process priority ladder.
Its hard to say, since I don't know the details of your app, but I think that you may want to consider a bit of a redesign.
As you have noticed, Activities are ephemeral. Generally speaking, a service should not (cannot) depend on a particular Activity being active.
In fact, a well-designed service should not depend on any particular activity at all.
I'm not sure I completely follow your question. However, when communicating from a Service to an Activity I use a broadcast receiver in the Activity class.
This can be created as follows:
// register the BroadcastReceiver in your activity class
this.receiver = new NotificationReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.LISTENER");
registerReceiver(receiver, filter);
// insert in your activity class
class MyReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
if(intent.hasExtra("command")) {
if(intent.getStringExtra("command").equals("userRegistered")) {
// insert code to do something when this intent is received
}
}
}
}
// insert in your service class to send message
Intent i = new Intent("com.example.LISTENER");
i.putExtra("command", "userRegistered");
sendBroadcast(i);

Receiver unregisterProblem

I am having the following problem in my app.
In on resume of my activity I register a broadcast receiver using this:
NetworkStateReceivernetworkStateReceiver = new NetworkStateReceiver(UIWrapperActivity.this);
filterConnectivity = new IntentFilter();
filterConnectivity.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkStateReceiver, filterConnectivity);
And then in onPause I unregister it:
unregisterReceiver(networkStateReceiver);
In broadcast receiver in the same activity I catch CONNECTIVITY_ACTION and show a certain activity (Something like noConnection) switching to this activity does trigger onPause() of first activity so receiver is unregistered but than when I try to close the noConnection activity using finish() it's just reopened and won't go away.
Does anyone know what am I doing wrong and why is my broadcast receiver not unregistered?
I eventually found out what I was doing wrong so if someone gets this same error, here is the solution.
I didn't finish the activity when I caught intent broadcast in the receiver so keep an eye out for that because if activity is still alive then it calls it's onResume() again and receiver gets re-registered.

Finish two activities on receive the same broadcast

I have a BroadcastReceiver which handles System Broadcasts like AC Connected and disconnected. The BroadcastReceiver receives POWER_CONNECTED and starts an Activity "MainActivity", which unlocks KeyGuard and acquires WakeLock. In the onCreate and in onResume I register dynamically a BroadcastReceiver to listen on POWER_DISCONNECTED.
The "MainActivity" starts a second "VideoPlayer Activity", which also register a BroadcastReceiver listening on POWER_DISCONNECTED.
When I send the ACTION_POWER_DISCONNECT over adb I see through LogCat that the "MainActivity" stops first. Why?
How can I handle that the "VideoPlayerActivity" finishes first?
Thanks
Look here (http://developer.android.com/reference/android/content/BroadcastReceiver.html):
Normal broadcasts (sent with Context.sendBroadcast) are completely asynchronous. All receivers of the broadcast are run in an undefined order, often at the same time. This is more efficient, but means that receivers cannot use the result or abort APIs included here.
You can't guarantee that VideoPlayerActivity will receive.
I would recommend to create a separate BroadcastReceiver (which isn't part of activities). And in this broadcast receiver do something like this:
videoPlayerActivity.finish();
mainActivity.finish();
Sure, you need to initialize both of these variables in onCreate or onResume of your activities.
Actually you Registered the Broadcast Receiver in your main activity so its passing the context of main activity in the BroadcastReceiver so i will able to finish only that activity.
So lets screw up this what you need to do just write these lines of code in the onReceive() of Power Disconnected action receiver:
public void onReceive(Context context, Intent intent) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startMain);
}
Enjoy

When to Register/Unregister Broadcast Receivers created in an activity?

I have a need to create a custom broadcast receiver in the onCreate event of an activity and obviously I need to unRegister the broadcast receiver in the onDestroy event of the activity
For clarity this is a snippet of the code I use
public class AnActivity extends Activity {
private ResponseReceiver receiver;
public class ResponseReceiver extends BroadcastReceiver {
public static final String ACTION_RESP =
"mypackagename.intent.action.MESSAGE_PROCESSED";
#Override
public void onReceive(Context context, Intent intent) {
// TODO Start a dialogue if message indicates successfully posted to server
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new ResponseReceiver();
registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
I have read that onPause/onResume and onStart/onStop events for the activity should also register and unregister the broadcast receiver.
I'm really wanting to understand what is considered to be the best practice for this and why.
You should register and unregister your receivers onStart() and onStop().
The only reason an Activity would register BroadcastReceivers is to use the events in some way on the current activity, to inform the User of an event. If onStop() has been called, then the Activity is no longer in the foreground, and therefore cant update the User.
If you want to receive broadcast events in the background you should consider using a service as indicated here.
Like Konstantin says, onDestroy() is not guaranteed to be called, and you could continue receiving broadcasts for a long time, when the Activity is no longer open.
As onDestroy() is not guaranted to be called you shall use onPause() to deregister. Consider lifecycle of your broadcast receiver: Do you need it to be active, only when your activity is in foreground? Then use onResume() / onPause()
The Android documentation doesn't prescribe a single place to register/unregister broadcast receivers, but it mentions both onStart()/onStop() and onResume()/onPause() as possibilities.
The biggest factor in making this decision is, when does your receiver need to be able to do its job? This will determine when to register and unregister it.
Does the receiver need to do something about the broadcast only when the activity is in focus? If so, you can register/unregister it in onPause()/onReceive(). (You can also use a longer lifetime such as onStart()/onStop(), but then you should check during the receiver's onReceive() whether the activity is in focus.)
Does the receiver need to do something when visible, even if it doesn't have focus (e.g. when a dialog is being shown)? If so, use onStart()/onStop() (or a longer lifetime, but again, the receiver's onReceive() should check whether the activity is visible).
Does the receiver need to know about the broadcast even when the activity isn't visible? For example, does it need to remember that something has happened, so that when the activity becomes visible, it can reflect the resulting state of affairs? Then you need to use onCreate()/onDestroy() to register/unregister. (Note there are other ways to implement this kind of functionality.)
If you register in onStart(), don't also register them in onResume(), because that would be redundant: onResume() is never called without onStart() being called first.
Also keep in mind that it's best to keep onPause() as light as possible:
onPause() execution is very brief, and does not necessarily afford
enough time to perform save operations. For this reason, you should
not use onPause() to save application or user data, make network
calls, or execute database transactions; such work may not complete
before the method completes. Instead, you should perform heavy-load
shutdown operations during onStop().
It's true that onDestroy() is not guaranteed to be called if the system kills your process in order to save memory. However if the process is killed, the process won't be receiving broadcasts anyway. In that case, is it really necessary to unregister broadcast receivers?
Android can kill your application with omitting onStop() method. The best way to solve that situation is register BroadcastReceiver in onResume() method and unregister in onPause().
You should register and unregister your broadcast in onResume() and onPause() methods.
if you register in onStart() and unregister it in onStop(). that time you will get following issue.
if your device screen is lock that time onStop() is called and if you unlock that time onStart() is never called. thats why you have register and unregister it in onResume() and onPause() methods.

Categories

Resources