BroadcastReceiver receives when service is started each time - android

I have a dynamically registered BroadcastReceiver on a Service. It gets AudioManager.RINGER_MODE_CHANGED_ACTION as IntentFilter. Every time I start the service I get the log message in onReceive() method. It works normally after that. I do not want it to receive once when service is started each time. Could you please tell me what I am missing here?
receiver=new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
Log.d("zil", "degisti");
}
};
IntentFilter filter=new IntentFilter(
AudioManager.RINGER_MODE_CHANGED_ACTION);
registerReceiver(receiver,filter);

The intent you are interested in, AudioManager.RINGER_MODE_CHANGED_ACTION, is "sticky". That means that the system always keeps the last broadcast sent and whenever a BroadcastReceiver is registered that is interested in that Intent, it receives it right away. This is a very useful feature but sometimes it isn't what you want ;-)
I assume that you are only interested in actual "change" events. In this case you need to ignore the "current" event and listen only for any events that happen in the future. Lucky for you, there is a solution:
In 'onReceive()' do the following:
if (isInitialStickyBroadcast()) {
// Ignore this one as we aren't interested in the current state
} else {
Log.d("zil", "degisti");
// Do whatever you want to do with the event here
}

unregisterReceiver(receiver);
this probably wont work because you created an Anonymous inner class implementation of BroadcastReciever. instead create a nested/private class that extends BroacastReceiver in the activity where you want your service started. Then dynamically register and unregister your receivers in the Activity lifecycle callbacks

Related

Activity Listen for broadcast receiver

So I have broadcast receiver that is getting started on boot. I have an activity that using the information being collected by the broadcast receiver. I want the activity to be able to update its recycler view every time the broadcast receiver is called, the problem is the activity has no reference to the broadcast receiver. Is there a way that I can have my activity listen for the broadcasts and update itself?
The only thing I can think of is having the activity run a repeating task that will try to update itself with new information. This doesn't seem like a good solution to me.
the best approach is to register a BroadcastReceiver - see documentation on this. In your case you'd want to Programmatically register a broadcast receiver so that the onReceive(Context context, Intent intent) from inside the Activity class. In this way, you can then update the Recyclerview as you desire. Something like:
public void onCreate(Bundle savedInstanceState){
...
IntentFilter filter = new IntentFilter();
//you may want to set whatever filters here...
//define the broadcast receiver
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//here you can update the RecyclerView as you desire using intent's data
}
};
//register the broadcast receiver
registerReceiver(receiver, filter);
}
I strongly recommend that you go through this nice BroadcastReceiver tutorial.
Enjoy.
The broadcast receiver registered for BOOT_COMPLETED action has nothing to do with the activity, it's a separate component. So, yes, you don't have a reference to your activity and you should not run any periodical task.
What I would do is to write the collected data to the database or shared preferences and then read it when your activity is actually on the screen.
If you use an SQLite database you can use a ContentObserver to notify your activity about changes to the underlying data. This works great with loaders.
In case of shared preferences you can use a OnSharedPreferenceChangeListener registered in your activity.

Android sendBroadcast - waiting for BroadcastReceiver to finish

I'm using a BroadcastReceiver in my Android app which simply contains the following piece of code:
public BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
GcmIntentService.isHandled = true;
Toast.makeText(context, "broadcast receiver test", Toast.LENGTH_SHORT).show();
}
}
I'm using this receiver to determine if my activity is running and carry out some updates in a ListView without having any notifications produced by GcmIntentService.
With the code being simple so far, only creating a toast message, I'm unable to catch the boolean value from GcmIntentService.isHandled as soon as the sendBroadcast is invoked.
Is it possible in any way to determine if the code for my receiver has finished running. I understand that sendBroadcast is an asynchronous call, and I'm making use of Thread.sleep(1000) so far to wait for the isHandled value, but it would be nice if there is a more reliable method on achieving this.
Any thoughts?
Your question can be divided to two parts:
1.How to know that if there is a receiver actually received the broadcast.
2.How should the receiver notify the service that message is been handled.
It seems difficult to achieve the first goal through standard Intent api, instead I suggest you may try the "observer pattern".
You may create a global Observable object in your Application and make your Activity implements Observer, register itself in onCreate() and unRegister in onDestory().Inside the Service you can check if there is an Activity running through countObservers() and then simply notify it.

Using a broadcast intent/broadcast receiver to send messages from a service to an activity

So I understand (I think) about broadcast intents and receiving messages to them.
So now, my problem/what I can't work out is how to send a message from the onReceive method of a receiver to an activity. Lets say I have a receiver as such:
public class ReceiveMessages extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if(action.equalsIgnoreCase(TheService.DOWNLOADED)){
// send message to activity
}
}
}
How would I send a message to an activity?
Would I have to instantiate the receiver in the activity I want to send messages to and monitor it somehow? Or what? I understand the concept, but not really the application.
Any help would be absolutely amazing, thank you.
Tom
EDITED Corrected code examples for registering/unregistering the BroadcastReceiver and also removed manifest declaration.
Define ReceiveMessages as an inner class within the Activity which needs to listen for messages from the Service.
Then, declare class variables such as...
ReceiveMessages myReceiver = null;
Boolean myReceiverIsRegistered = false;
In onCreate() use myReceiver = new ReceiveMessages();
Then in onResume()...
if (!myReceiverIsRegistered) {
registerReceiver(myReceiver, new IntentFilter("com.mycompany.myapp.SOME_MESSAGE"));
myReceiverIsRegistered = true;
}
...and in onPause()...
if (myReceiverIsRegistered) {
unregisterReceiver(myReceiver);
myReceiverIsRegistered = false;
}
In the Service create and broadcast the Intent...
Intent i = new Intent("com.mycompany.myapp.SOME_MESSAGE");
sendBroadcast(i);
And that's about it. Make the 'action' unique to your package / app, i.e., com.mycompany... as in my example. This helps avoiding a situation where other apps or system components might attempt to process it.
No offense, but your question is still damn vague. So, I'm going to outline a whole mess of scenarios and hope that one of them actually hits whatever problem you think you have.
Scenario A: Only The Activity
If you only need to receive the broadcast when you have an activity in the foreground, have the activity register the BroadcastReceiver using registerReceiver(). As #MisterSquonk indicated, you would register the receiver in onResume() and unregister it in onPause().
Scenario B: Activity If In Foreground, Else Other; Ordered Broadcast
If you want the foreground activity to handle the broadcast, but you want something else to happen if that activity is not in the foreground (e.g., raise a Notification), and the broadcast is an ordered broadcast (e.g., incoming SMS), then you would still use the Scenario A solution, but with a higher-priority IntentFilter (see setPriority()). In addition, you would register a BroadcastReceiver via a <receiver> element in the manifest, with a lower-priority <intent-filter> for the same broadcast. In the activity's BroadcastReceiver, call abortBroadcast() to consume the event and prevent it from reaching your manifest-registered BroadcastReceiver.
Scenario C: Activity If In Foreground, Else Other; Regular Broadcast
If Scenario B almost fits, but the broadcast you are listening for is not an ordered broadcast, you will need to start with Scenario B. However, have the broadcast that both receivers have in their respective filters be one of your own, using a private action string as #MisterSquonk suggested. In addition, have another BroadcastReceiver registered in the manifest, whose <intent-filter> is for the real broadcast you're listening for. That receiver would simply call sendOrderedBroadcast() to send out the ordered broadcast that the other receivers are listening on.
Scenario D: Activity Regardless of Foreground
If some activity of yours needs to know about the broadcast, and it does not matter whether or not it is in the foreground, you need to rethink what you mean by that. Usually, this really means that the broadcast affects your data model in some way, in which case your concern should not be to let the activities know, but rather to update your data model, and use your already-existing "let the activities know about the data model change" logic handle the rest.
If, however, you are convinced that this is not part of your data model, you can implement Scenario B or Scenario C, plus stick some information in a static data member. Your activities can examine that static data member in onResume() to pick up the information about the broadcast when they return to the foreground.
If you're thinking "but, what if my process is terminated between the broadcast and the other activity coming to the foreground?", then your broadcast really is updating your data model, per the opening paragraph of this scenario.
If you're thinking "but, I want to update an activity that is doing work in the background", then the activity in question is broken. Activities should never be doing work in the background. That work should be delegated to some form of service, and there's a whole related set of scenarios for getting a broadcast to the service.
To broadcast an intent:
Intent intent = new Intent("com.yourcompany.testIntent");
intent.putExtra("value","test");
sendBroadcast(intent);
To receive the same intent use:
IntentFilter filter = new IntentFilter("com.yourcompany.testIntent");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String value = intent.getExtras().getString("value");
}
};
registerReceiver(receiver, filter);
Possibly not relevant at the time of the question being asked but there is now the LocalBroadcastManager in the Android Support Package.
Works pretty much the same way as normal broadcasts but all "chatter" is local to the app it is running in.
Advantages:
You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.
It is more efficient than sending a global broadcast through the system.
Example:
Intent i = new Intent("my.local.intent");
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
and to receive
receiver = new MyBroadcastReceiverToHandleLocalBroadcast();
IntentFilter i = new IntentFilter();
i.addAction("my.local.intent");
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, i);

What's the right way to send messages from my IntentService back to an Activity?

I have an app in which the main Activity starts an AlarmReceiver that calls an IntentService that runs in the background and does stuff. I'm unclear on what the correct way is to check on the IntentService's actions and present the end-user with some feedback in the visible Activity that they're in, on the IntentService's current state. In my ideal world there can be an icon somewhere on the screen that I can set to notify the user of what's going on with the IntentService. I don't need the user to be able to *do anything, just have feedback.
All advice welcome.
Android has a notification API, which is even easy to use - Creating Status Bar Notifications.
If you want your activity to receive updates from the service, I would suggest using broadcasts and broadcast receivers.
How to send a broadcast intent:
Intent i = new Intent("your.action");
sendBroadcast(i);
To receive this broadcast within your activity, you have to implement a broadcast receiver:
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//
}
};
which you have to register...
registerReceiver(myReceiver, new IntentFilter("your.action"));

A service will always receive the Broadcast Action that registered for?

I have created a service which is supposed to receive the android.bluetooth.device.action.ACL_DISCONNECTED/ACL_CONNECTED events.
I am aware that services in android may be restarted/stopped when android decides.
However, I am wondering whether a service is always guaranteed to receive the events it registered for, even it has been killed by android?
I assume this means that android will need to restart a killed service which has registered to listen to events when that event takes place.
Is the above assumption correct ?
Thank you very much for the quick reply.
Let me give some more information, sample of the code follows:
public class my_service extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
IntentFilter filterDisconnected = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED);
this.registerReceiver(mReceiverDisconnected, filterDisconnected);
...
}
private final BroadcastReceiver mReceiverDisconnected = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
...
}
}
...
}
So with this code the BroadcastReceiver is implemented within the service class.
This code is working fine under normal cirmustances but are you saying that this is not proper and a different class (BroadcastReceiver ) is needed ?
If the above is proper, i am wondering if this service class is stopped for any reason, when the relevant event is raised, the class will be restarted and the BroadcastReceiver will get the event.
Hi all, i have created a service which is supposed to receive the android.bluetooth.device.action.ACL_DISCONNECTED/ACL_CONNECTED events.
That should not be possible. Those are documented as being broadcast actions; if true, then they can only be picked up by a BroadcastReceiver.
However, i am wondering whether a service is always guaranteed to receive the events it registered for, even it has been killed by android ?
Again, services should never "receive" those events directly.
However, if you create a BroadcastReceiver and put it in the manifest with an <intent-filter> for your desired broadcasts, then that BroadcastReceiver is "guaranteed to receive the events it registered for", and that BroadcastReceiver can call startService() to send a command to an IntentService if desired.

Categories

Resources