I have an Activity in which I am registering a BroadcastReceiver locally as follows:
public class SomeActivity extends Activity{
public static final String PERFORM_SOME_ACTION = "PERFORM_SOME_ACTION";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.some_activity_layout);
.....
.....
IntentFilter filter = new IntentFilter();
filter.addAction(PERFORM_SOME_ACTION);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// perform some action ...
}
};
registerReceiver(receiver, filter);
}
.....
.....
}
And I have a Service from which I broadcast an Intent as follows:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent i = new Intent(SomeActivity.PERFORM_SOME_ACTION);
sendBroadcast(i); /* Send global broadcast. */
return START_STICKY;
}
This works as intended. After having implemented this, I realized that a local broadcast would be more appropriate for this situation:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent i = new Intent(SomeActivity.PERFORM_SOME_ACTION);
LocalBroadcastManager.getInstance(this).sendBroadcast(i); /* Send local broadcast. */
return START_STICKY;
}
Unfortunately, the above scheme doesn't work. A global broadcast is sent every time, while a local broadcast is apparently never sent/received.
What am I missing here? Can't local broadcasts be sent between two distinct app components, like two separate Activitys or from a Service to an Activity? What am I doing wrong??
Note:
As per the documentation, it is more efficient and more to the point to send a local broadcast (an intra-app broadcast whose scope is restricted to the app's own components) rather than a global broadcast (an inter-app broadcast which is transmitted to every single app on the phone) whenever we do not need the broadcast to propagate outside the application. This is the reason for making the aforementioned change.
What am I missing here?
Use LocalBroadcastManager for registering LocalBroadcast, currently using registerReceiver method of Activity which is used for registering global Broadcast:
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
Related
#Override
protected void onStart() {
startService(new Intent(this, jam_service.class));
super.onStart();
As soon as I create my main activity, I start my service that looks like this
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter intentFilter = new IntentFilter(myBroadcastReceiver.BroadcastTypes.METADATA_CHANGED);
IntentFilter(myBroadcastReceiver.BroadcastTypes.PLAYBACK_STATE_CHANGED);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(broadcastReceiver, intentFilter);
return START_STICKY;
}
Which registers this broadcast receiver
public void onReceive(Context context, Intent intent) {
c.writeNewUser(intent.getStringExtra("track"),"user", intent.getStringExtra("track"));
The broadcast receiver detects when the user changes songs in Spotify, and it works sometimes for a short period of time after launching my app and then switching to Spotify, or when my app is open and changing Spotify songs from the notification bar. I want this receiver to never stop listening to broadcasts, even after my app has been in the background for a while. Why does it stop working?
This is for a GPS. I have a parent class with an embedded receiver class, and a separate LocationTrackingService class that handles the GPS stuff. I need to Broadcast the mileage traveled to update the UI, but the broadcast is never received. This is the only BroadcastReceiver in the project. I guess I could set a timer to have my ServiceConnection check every couple of seconds and grab the new mileage, but that's bad coding.
Nothing is in the Manifest because I'm registering and unregistering dynamically.
public class Parent
{
GPSReceiver gpsreceiver;
public class EmbeddedReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context arg0, Intent intent)
{
Bundle extras = intent.getExtras();
if (extras != null) {
distance = extras.getDouble(LocationTrackingService.UPDATE_MILEAGE_MESSAGE);
}
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
gpsReceiver = new EmbeddedReceiver();
}
private void gpsStart()
{
if (gpsReceiver != null) {
intentFilter = new IntentFilter();
intentFilter.addAction("don't know what goes here");
LocalBroadcastManager.getInstance(this).registerReceiver(gpsReceiver, intentFilter);
}
}
private void gpsStop()
{
if (gpsReceiver != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(gpsReceiver);
}
}
}
public class LocationTrackingService extends Service
{
private LocalBroadcastManager broadcaster;
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);
broadcaster = LocalBroadcastManager.getInstance(this);
return START_STICKY;
}
.... code
private void sendResult(String message)
{
Intent i = new Intent("ParentActivity");
i.setAction("ParentActivity");
if (message != null) {
i.putExtra(message, mileageRunningTotal);
}
broadcaster.sendBroadcast(i);
}
}
When I follow the code into LocalBroadcastManager, on line 215 it does mActions.get(intent.getAction() to get an ArrayList<ReceiverRecord>, and it's null, but I don't know why.
I appreciate any help you can give.
Broadcasts work in such a way that the action acts as a trigger for the receiver. In other words, there are tons of broadcasts being sent around throughout your phone at any given time, the goal of the receiver is to catch the broadcast with the corresponding action when it flies by. It will let all other broadcasts continue through without interruption. Once it finds the one it is looking for, it will receive it and perform the onReceive() functionality.
Though an action can be any string key you care for it to be, it is advised to add in your package name. This gives specificity to your broadcast and allows your broadcast to be more easily managed in the barrage of broadcasts that your phone is sending. This is important as broadcasts can be sent between applications. It makes it so you avoid the following scenario
Application A sends out a system broadcast with action "SOME_ACTION" which we have no interest in. Application B will also be sending out a local broadcast with action "SOME_ACTION" which we are awnt to receive. We will setup Receiver 1 to look for and receive the action "SOME_ACTION" from Application B. However, because of conflicting actions, when Application A sends out a broadcast of "SOME_ACTION", we will inappropriately receive it in Receiver 1 and perform our onReceive() functionality as though we had just received a local broadcast from Application B.
Following recommended convention, you avoid the above situation by doing the following
Instead of setting your action as "SOME_ACTION", it would be set to "com.app_b.package.SOME_ACTION". That way when the broadcast action "com.app_a.package.SOME_ACTION" passes by, it won't be confused for our action and will be allowed to pass.
There may be other reasons for using package name, and this may not be the best of them, but to the best of my knowledge this is the reasoning behind the convention.
I cant see the declaration for the broadcaster object.
broadcaster.sendBroadcast(i);
Is it a Local Broadcast Manager instance?
If not it won't work.
i have created one service by extending Service in android and i am sending Message to service using Messenger and Handler.
But the issue (which is a common behavior though) is whenever i have to send message to Service i have to bind it and when i go out of activity i have to unbind it which eventually destroys the service itself.
i can keep running service in background by fringing startService method but is there any way to send Messages to service without using bind as i don't want to destroy the service when i go out of activity.
LocalBroadcastManager is a great way to send messages/data,
In your service class create a private broadcastreciever and string for the intent action name:
public static String MSERVICEBROADCASTRECEIVERACTION ="whatevs";
private BroadcastReceiver mServiceBroadcastReceiver= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("foo","onReceive called");
Log.d("foo","extra = " + intent.getStringExtra("foo")); // should print out " extra = bar"
}
};
And register it in your onCreate
#Override
public void onCreate() {
// your other code...
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceBroadcastReceiver, new IntentFilter(ServiceClassName.MSERVICEBROADCASTRECEIVERACTION));
}
And De-register it in onDestroy()
#Override
public void onDestroy() {
// your other code...
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
}
As for sending messages to it, from an activity or fragment:
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
Intent intent = new Intent(ServiceClassName.MSERVICEBROADCASTRECEIVERACTION);
// add some data
intent.putExtra("foo","bar");
lbm.sendBroadcast(intent);
HTHs you send data without needing to bind!
Unbind Service will not destroy the service. it will disconnect the service connection between the activity and service
Make sure you return START_STICKY to keep your service running
#Override
public int onStartCommand(Intent intent, int flag, int startId)
{
return START_STICKY;
}
Also make sure your running the service as foreground
using notification to keep running the service after the application is removed from stack.
startForeground(1000,mBuilder.build()); // mBuilder - notification builder
public class MainActivity extends Activity {
public TextView batteryTxt;
private BroadcastReceiver receiver;
BroadcastReceiver mybroadcast = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int batterylevel = intent.getIntExtra("level", 0);
batteryTxt.setText("Battery Level: " + Integer.toString(batterylevel) + "%");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
batteryTxt = (TextView) findViewById(R.id.textView1);
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(mybroadcast, filter);
}
}
Eventhough i have not used intent.putExtra() in above program, how intent.getIntExtra("level", 0) is working?
It's an IntentFilter, which sends an Intent to the BatteryManager to check ACTION_BATTERY_CHANGED. The BatteryManager then calls intent.putIntExtra to put the int that you're reciving in the Intent.
The intent is what your BroadcastReceiver receives from the system, when the action "ACTION_BATTERY_CHANGED" is performed. It's the information about battery level in this case, and "0" is the default value (in case there isn't extra named "level"). The intent is not created by any activity in this app.
You need to read the documentation on BroadcastReceivers and Intents.
http://developer.android.com/reference/android/content/BroadcastReceiver.html
http://developer.android.com/reference/android/content/Intent.html
Essentially these two mechanisms act as Android's preferred method of transferring state between applications and processes.
In short:
Broadcast Receivers are registered for Intents, and whenever an intent is "Fired" or "Launched" which corresponds to the "Mime-Type" for which your intent is registered, that Broadcast Receiver will be activated. At this time your Broadcast Receiver will be given the opportunity to handle state passed to it via the intent which was sent.
In your case:
You have created a Broadcast Receiver which is registered (presumably) for the Battery Service intents. That means every time the battery service sends out an Intent to all interested parties you'll receive an a message. The Battery Service includes in it's intent certain data which is useful to an application,service or process which is interested in the state of the Battery. In this case it is the "level".
I've a local service that is started in my main activity. The service is responsible for network I/O. It also interacts with other activities in my application. Till, now the service was only "providing" data to activity (using callbacks and not Intents.)
Now I need to send data (custom objects) from my activities to the service. I understand one way to do it using Intents. I know it is possible to receive an Intent in the service by overriding the onStartCommand() in my service. But it's not clear to me if the onStartCommand will be invoked every time I broadcast an Intent from my sending activity. Can a Service also be BroadcastReceiver ? If yes - how ?
Thanks.
You can create a BroadcastReceiver object in the service and register it to listen to any broadcast event you want. It's something like this:
BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//handle the broadcast event here
}
};
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mScreenStateReceiver, filter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mScreenStateReceiver);
}
Regards,