First of all I wanted to give codes here but the codes are way to long, it can be found here
http://www.c-sharpcorner.com/article/creating-and-scheduling-alarms-in-android/
The codes in the article doesn't create service.
As per my understanding, BroadcastReceiver is used to serve an activity based on its corresponding Service ( via an intent ).
Normally we would declare such :
Intent serviceIntent = new Intent(MainActivity.this, CustomeService.class);
startService(serviceIntent);
registerReceiver(mReceiver, mIntentFilter);
where mReceiver will be something like :
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
}
But there's something confusing me in AlarmManager class in the example that I shared by the link :
intent = new Intent(this, MyBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(
this.getApplicationContext(), 280192, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + (i * 1000), 10000
, pendingIntent);
The line that is confusing me is this :
intent = new Intent(this, MyBroadcastReceiver.class);
the type of this MyBroadcastReceiver.class is BroadcastReceiver itself, and not Service.
So where's the Service that this MyBroadcastReceiver.class received broadcast from then?
Does BroadcastReceiver somehow create its own service?
the type of this MyBroadcastReceiver.class is BroadcastReceiver itself, and not Service
Correct. It is being used with PendingIntent.getBroadcast(), notgetService()`.
So where's the Service that this MyBroadcastReceiver.class received broadcast from then?
Few broadcasts are sent by some Service, though that is certainly possible. In this case, the broadcast is being sent from a system process, as part of sending the PendingIntent, when the alarm time comes around.
Does BroadcastReceiver somehow create its own service?
I am not sure what you mean by "create" here. A BroadcastReceiver may delegate its work to a Service. That is a common pattern with AlarmManager: have the alarms trigger a WakefulBroadcastReceiver, which in turn delegates work to an IntentService. In that case, the reason for the indirection stems from the way that AlarmManager works with WakeLocks.
Related
With the following code, the AlarmReceiver.onReceive() is not called when it should be after the app is killed manually (to simulate the OS killing the app on a whim).
What must I do so that the AlarmReceiver still works after the OS kills it?
Manifest:
<receiver
android:name="abc.def.AlarmReceiver"
android:enabled="true"
android:exported="false"
/>
AlarmReceiver:
public class AlarmReceiver extends BroadcastReceiver {
public void setupAlarm(Context context, int intervalMS) {
this.interval = interval;
Calendar updateTime = Calendar.getInstance();
updateTime.add(Calendar.SECOND, 5);
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
PendingIntent recurringDownload = PendingIntent.getBroadcast(context, 123, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarms.setRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), intervalMS, recurringDownload);
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Alarm", "hello world!");
}
}
When you kill it manually, you're putting the app into the forced stop state. That stops all Receivers and Services until you start it by hand again. That's not the same as being killed by the OS.
Normal process termination(by OS) does not cancel scheduled AlarmManager events. So, the alarms would still work after OS kills the process.
If you are manually force-closing the app, your alarms are unregistered. And, on Android 3.1+, you have to manually launch one of the activities to register them again.
So by killing the app manually you are not exactly simulating the OS killing the app
android:exported="false" means you don't allow your app to receive any events from system. Change it to true
One more thing, make sure you call setupAlarm in Context
From the documentation of google
Whether or not the broadcast receiver can receive messages from sources outside its application — "true" if it can, and "false" if not. If "false", the only messages the broadcast receiver can receive are those sent by components of the same application or applications with the same user ID.
The default value depends on whether the broadcast receiver contains intent filters. The absence of any filters means that it can be invoked only by Intent objects that specify its exact class name. This implies that the receiver is intended only for application-internal use (since others would not normally know the class name). So in this case, the default value is "false". On the other hand, the presence of at least one filter implies that the broadcast receiver is intended to receive intents broadcast by the system or other applications, so the default value is "true".
This attribute is not the only way to limit a broadcast receiver's external exposure. You can also use a permission to limit the external entities that can send it messages (see the permission attribute).
All is accordingly but in the code may be you have not called your setupAlarm() method in onRecieve().
public class AlarmReceiver extends BroadcastReceiver {
public void setupAlarm(Context context, int intervalMS) {
this.interval = interval;
Calendar updateTime = Calendar.getInstance();
updateTime.add(Calendar.SECOND, 5);
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
PendingIntent recurringDownload = PendingIntent.getBroadcast(context, 123, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarms.setRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), intervalMS, recurringDownload);
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Alarm", "hello world!");
setupAlarm(context,2000);//May be this line is missing.
}
}
I want to use AlarmManager to schedule a repeating task. Basically, I have this code:
Intent intent = new Intent(INTENT_ACTION_TICK);
// The following line prevents the broadcast receiver from being notified:
intent.setClass(context, MyScheduler.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, intervalInMs, intervalInMs, pendingIntent);
I register MyScheduler as a broadcast receiver in its constructor:
context.registerReceiver(this, new IntentFilter(INTENT_ACTION_TICK));
Everything works as expected (receiver is triggered) unless I add the intent.setClass. Fine with me, however, I distinctly remember reading that you should use explicit intents (intent.setClass) for security reasons.
Is this something I have to consider for my use case?
I have an AlarmManager that sets a repeating alarm for the purpose of periodically querying a server.
private AlarmManager alarmManager;
private PendingIntent pendingIntent;
alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent photosIntent = new Intent(this,AlarmReceiver.class);
//startService(photosIntent);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),0,photosIntent,0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime(),
10000, pendingIntent);
And I start an IntentService within the AlarmReceiver's onReceive() method. AlarmReceiver is a BroadcastReceiver. Here is the onReceive() method:
#Override
public void onReceive(Context context, Intent intent) {
Intent photosIntent = new Intent(context,JSONPhotosParser.class);
context.startService(photosIntent);
}
Now, this is something crazy I want to do, as it is not very practical. Is there any way I can stop my AlarmManager from within the BroadcastReceiver. I can also think of a practical scenario where such an action would be required. Say I am querying the status of a network connection using ConnectivityManager and if a connection exists I would start an IntentService that queries a server (which is my current scenario). If network status returns false, I would like to stop the repeating alarm set by the AlarmManager.
Is this possible within the BroadcastReceiver ? I understand that an AlarmManager can be removed using cancel(PendingIntent operation). But how do I create PendingIntent inside the BroadcastReceiver ?
Any help on this would be most appreciated. From an Android noob.
refer this link :
AlarmManager.cancel (PendingIntent operation)
http://developer.android.com/reference/android/app/AlarmManager.html#cancel%28android.app.PendingIntent%29
I've been struggling with this for a couple of days. What I want to do is run a service periodically, about 2-3 minutes apart. I have an Activity that is responsible for the interface and setting up the first alarm.
The alarm is configured by a BroadcastReceiver which looks like this:
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String message = "Alarm worked";
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
setAlarm(context);
}
public void setAlarm(Context context){
AlarmManager am = (AlarmManager) context.
getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent dailyUpdater = new Intent(context, DiscoveryService.class);
context.startService(dailyUpdater);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (1000 * 30) , pi);
}
}
I've tried using setRepeating for AlarmManager, but it still has the same effect. What happens is that the AlarmManager works how it should, it fires an Intent which the receiver gets and executes onReceive periodically, as it should. However, it executes the service only the first time. After the first time, the alarms still go off, but the service is not executed.
I read some threads from people with similar problems, and one of them mentioned that PendingIntent lasts for only one send. Thus, I opted out to setting the alarm every time so I can set pendingIntent flag for updating every time.
I tried making my service an intentService, which is fine, but then my bluetooth scanner inside the service does not work because intentService thread terminates without waiting for my bluetooth discovery to finish.
Anyone have any idea what can help me?
Here is part of my service:
public class DiscoveryService extends Service {
public void onCreate() {
super.onCreate();
Toast.makeText(this, "MyAlarmService.onCreate()",
Toast.LENGTH_LONG).show();
findEverything();
}
}
EDIT: This is the code that I currently have.
public void onReceive(Context context, Intent intent) {
String message = "Alarm worked";
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
Intent dailyUpdater = new Intent(context, DiscoveryService.class);
context.startService(dailyUpdater);
}
public void setAlarm(Context context){
// get a Calendar object with current time
AlarmManager am=(AlarmManager)context.
getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
(1000 * 30) , pi);
}
What happens is that the AlarmManager works how it should, it fires an Intent which the reciever gets and executes onReceive periodically, as it should. However, it executes the service only the first time. After the first time, the alarms still go off, but the service is not executed.
You are calling startService() once when you are scheduling the alarm. You are not calling startService() at all from your BroadcastReceiver. Yet you are scheduling the alarm via the BroadcastReceiver. Hence, when the alarm goes off, the service will not be sent a command, because you are not sending it a command.
I read some threads from people with similar problems, and one of them mentioned that PendingIntent lasts for only one send.
That is only if you use FLAG_ONE_SHOT.
Anyone have any idea what can help me?
Call startService() from your onReceive() method, instead of from your setAlarm() method. Also, add in all the WakeLock management logic, since you are using a _WAKEUP alarm and you are not able to use my WakefulIntentService.
I have an ImageView in my activity that shows an "active" symbol when a service is activated.
After the Service has been executed the ImageView should go back to the "inactive" Symbol.
AlarManager that starts Service:
context = this;
Intent intent = new Intent(context, AlarmReceiver.class);
sender = PendingIntent.getBroadcast(context, INTENT_CODE, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calNew.getTimeInMillis(), sender);
setImage(active);
AlarmManager:
#Override
public void onReceive(Context context, Intent intent) {
Intent wakeupIntent = new Intent(context, WakeupActivity.class);
context.startService(wakeupIntent);
}
How can I make the Image change back to inactive after the service has been executed? I tried to create a new Runnable and then postDelayed(runnable, calNew.getTimeInMillis()) using a handler. Actually it didn't work, nothing happened. Is there a better way to do this?
How can I make the Image change back to inactive after the service has been executed?
Step #1: Add the Android Support package to your application.
Step #2: Have your activity register a BroadcastReceiver with LocalBroadcastManager in onResume() and unregister it in onPause().
Step #3: Have your service send a broadcast via LocalBroadcastManager when its work is complete, to be picked up by the activity's BroadcastReceiver.
Here is a sample project demonstrating this technique.