I have an activity that starts a service. This service (Service-A) registers a broadcastreceiver with an intentfilter "ACTION_SCREEN_ON". When this broadcastreceiver runs it starts another service (Service-B) which updates my widgets periodically until screen is off.
This is how i register my broadcast receiver & how i implement my boradcast receiver
//Service that register my boradcastreceiver
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
IntentFilter filterScreen = new IntentFilter(Intent.ACTION_SCREEN_ON);
filterScreen.addAction(Intent.ACTION_SCREEN_OFF);
filterScreen.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filterScreen.addAction(Intent.ACTION_TIME_CHANGED);
mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filterScreen);
return START_STICKY;
}
//My broadcastreceiver
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
{
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
{
Intent service = new Intent(context, MinuteUpdateService.class);
context.startService(service);
}
else if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED))
{
Intent service = new Intent(context, MinuteUpdateService.class);
service.putExtra("oneTimeRun", true);
context.startService(service);
}
else if (intent.getAction().equals(Intent.ACTION_TIME_CHANGED))
{
Intent service = new Intent(context, MinuteUpdateService.class);
service.putExtra("oneTimeRun", true);
context.startService(service);
}
}
This flow usually works well. However sometimes my boradcastreceiver does not run as expected. It does not receive ACTION_SCREEN_ON broadcast. Usually this happens after long sleeps.
I suppose that Service-A killed/stopped by system and my broadcast is unregistered.
Is there any method that make this service/broadcast persistent? or is there another way which is more suitable for my intent?
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?
I was working with broadcast receiver and background services. So, When one my activity goes onPause(), I start my service and service sends a broadcast. Now, my broadcast receiver is in the same class as my service. I am receiving my service call, but I am unable to receive the broadcast info. Here is the code I have been working on..
[EDITED]
private String notifier = "ninja.ibtehaz.thenewproject.Activities.activityNew";
#Override
protected void onHandleIntent(Intent intent) {
boolean flag = ProjectApp.getInstance().isActivityVisible();
Log.e("rainbow", "onHandleIntent");
if (!flag) {
//start emergency activity
Log.e("rainbow", "starting activity");
Intent broadcastIntent = new Intent(notifier);
sendBroadcast(broadcastIntent);
}
}
[EDITED] on activityNew class >
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("rainbow", "In Method: Service started");
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, filter);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("rainbow", "In Method: onReceive");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.e("rainbow","Screen went OFF");
}
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Log.e("rainbow","Screen went ON");
}
}
};
and the manifest file : [EDITED]
<service android:name=".Activities.ServiceBackground">
</service>
<receiver
android:name=".Activities.ActivityEmergency"
android:theme="#android:style/Theme.NoDisplay">
</receiver>
here is my logcat info :
E/rainbow: onHandleIntent
E/rainbow: starting activity
I am not getting anything after that..
I know this might not be the best practice, I just started working with these things.
Thank you for your help. Cheers!
You are registering a BroadcastReceiver with an IntentFilter which only contains Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON, but no ninja.ibtehaz.thenewproject.Activities.activityNew. It means this BroadcastReceiver can only be invoked when Intent.ACTION_SCREEN_OFF or Intent.ACTION_SCREEN_OFF is broadcast.
Now pay attention to your sendBroadcast code:
Intent broadcastIntent = new Intent(notifier);
sendBroadcast(broadcastIntent);
You are broadcasting an action "ninja.ibtehaz.thenewproject.Activities.activityNew", which can't match the IntentFilter bound with the BroadcastReceiver you have registered.
Try to use these codes:
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(notifier);
registerReceiver(receiver, filter);
Broadcast Limitations : With limited exceptions, apps cannot use their manifest to register for implicit broadcasts. They can still register for these broadcasts at runtime, and they can use the manifest to register for explicit broadcasts targeted specifically at their app.
Android documentation: https://developer.android.com/about/versions/oreo/background
Try registering like below dynamically in Application Activity/Service instead of Manifest.
BroadcastReceiver receiver = new NotificationReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_UPDATE_NOW);
context.registerReceiver(receiver, filter);
You are registering your receiver inside the processing an intent method ;-) This would not work, definitely.
You must register your receiver earlier, ex. in onCreate() method.
My Application class creates an alarm and receives the system broadcast once per day. In the onReceive() it sends an application broadcast that is received by my MainActivity class.
The problem is that the onReceive() in the MainActivity class is continually called whenever an orientation change occurs. I understand why onResume() is called across orientation changes, but I don't understand why onReceive() is also getting called.
I assumed that because the Application class only sends out the local broadcast once, my
MainActivity would only receive the broadcast once.
Does anyone know why onReceive() in my MainActivity class is continually called?
Here is the onCreate() in my Application class:
#Override
public void onCreate()
{
super.onCreate();
// register a receiver in the Application class to receive a broadcast
// at the start of each day
IntentFilter intentFilter = new IntentFilter(START_OF_DAY_ACTION);
startOfDayReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(TaskReminderApp.this,
"Application: startofday broadcast received",
Toast.LENGTH_LONG).show();
// send a broadcast to MainActivity
Intent i = new Intent();
i.setAction(TEST_ACTION);
context.sendBroadcast(i);
}
};
this.registerReceiver(startOfDayReceiver, intentFilter);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 19); // for testing purposes
calendar.set(Calendar.MINUTE, 51); // for testing purposes
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Intent intent = new Intent(START_OF_DAY_ACTION);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
}
Here is onResume() and onPause() in MainActivity:
#Override
protected void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter(TEST_ACTION);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent)
{
// This is getting called on every orientation change
// and every time the activity resumes.
Toast.makeText(MainActivity.this,
"MainActivity: broadcast received",
Toast.LENGTH_LONG).show();
}
};
this.registerReceiver(receiver, intentFilter);
}
#Override
protected void onPause()
{
super.onPause();
// I thought this might be the problem, but it makes no
// difference if I comment it out.
this.unregisterReceiver(receiver);
}
Because you need to create the Receiver in your onCreate(). Else it will be created again and again and again..
The registering is just fine, same as the unregistering.
I solved this by sending a local application broadcast instead of a system broadcast.
In my class that extends Application, I send a local broadcast like this:
Intent i = new Intent(TEST_ACTION);
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
Then in my MainActivity class, I define a BroadcastReceiver like this:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(MainActivity.this,
"MainActivity: broadcast received",
Toast.LENGTH_LONG).show();
}
};
I register the receiver in MainActivity's onCreate():
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
new IntentFilter(TEST_ACTION));
Then I unregister the receiver in MainActivity's onDestroy():
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
It works well now and I only receive a single broadcast.
I've a Broadcast receiver:
public class ScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//Do something
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Intent start=new Intent(context,MainActivity.class);
context.startActivity(start);
}
}
}
And, in my activity, into onCreate():
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
ScreenReceiver mReceiver=new ScreenReceiver();
registerReceiver(mReceiver, filter);
The problem is that, when my activity is displayed, the receiver performs correctly the action, but when it is in background, sometimes nothing happens.
What could be the issue?
Most likely, when your app goes into the background Android kills it to free up resources. Try starting a foreground service attached to an ongoing notification from your Activity, and register the BroadcastReceiver in that.
I've a problem with an app I'm coding.
I need to receive ACTION_SCREEN_ON, ACTION_SCREEN_OFF and ACTION_USER_PRESENT intents everytime they're broadcasted, so my app of course stays in background. At the moment my app is made by a settings activity and a service. ScreenReceiver is a BroadcastReceiver that gets the ACTION_SCREEN_* intents, while UnlockReceiver gets the ACTION_USER_PRESENT intent. The service registers and unregisters the receivers:
public class MainService extends Service {
ScreenReceiver screenReceiver = null;
UnlockReceiver unlockReceiver = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onStart(Intent intent, int startId) {
doStart();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doStart();
return START_STICKY;
}
public void doStart() {
if(screenReceiver != null && unlockReceiver != null)
return;
IntentFilter filter;
if(screenReceiver == null) {
filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
screenReceiver = new ScreenReceiver();
registerReceiver(screenReceiver, filter);
}
if(unlockReceiver == null) {
filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_PRESENT);
unlockReceiver = new UnlockReceiver();
registerReceiver(unlockReceiver, filter);
}
}
#Override
public void onDestroy() {
if(screenReceiver != null)
unregisterReceiver(screenReceiver);
if(unlockReceiver != null)
unregisterReceiver(unlockReceiver);
}
}
But sometimes Android kills my service to free some RAM and then restarts it. The time between the kill and the respawn is usually around 5 seconds, but sometimes this can be enought to miss some intents causing problems to the users of my app. Those intents can be registered only trought registerReceiver, so I can't register them in the manifest. How could I listen to those intents without being killed or missing some?
Thanks!
How could I listen to those intents without being killed or missing some?
You don't. You rewrite your app to either not use those broadcasts or to be more resilient in the case of missing broadcasts. After all, it is not just "Android kills my service to free some RAM and then restarts it", but task managers and the like that can get rid of your service.