I have implemented the alarm manager to wake up the background services every 15 mins periodically. It is working fine, but since the inclusion of DOZE mode Android 6.0, the seems like behaving strange and not waking up in every 15 mins. Although, I am using the method alarm.setExactAndAllowWhileIdle(), but still not working in Idle state
here is my method for implementing Alarm Manager
private void serviceRunningBackground()
{
final Intent restartIntent = new Intent(this, service.class);
restartIntent.putExtra("ALARM_RESTART_SERVICE_DIED", true);
alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Handler restartServiceHandler;
restartServiceHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
pintent = PendingIntent.getService(getApplicationContext(), 0, restartIntent, 0);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
Log.d(TAG, " Marshmellow "+ TIMER_START_TIME);
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, 900000, pintent);
} else {
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 900000, pintent);
}
sendEmptyMessageDelayed(0, TIMER_START_TIME);
}
};
restartServiceHandler.sendEmptyMessageDelayed(0, 0);
}
Any help would be appreciated..thanks
Try this:
public class PollReceiver extends WakefulBroadcastReceiver{
static final String PERIOD = "period";
#Override
public void onReceive(Context context, Intent intent){
startWakefulService(context,new Intent(context,MyService.class));
long period = intent.getLongExtra(PERIOD,-1);
if(period>0){
scheduleExactAlarm(context,(AlarmManager)context.getSystemService(Context.ALARM_SERVICE),period)
}
}
static void scheduleExactAlarm(Context context,AlarmManager alarms, long period){
Intent i = new Intent(context,PollReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context,0,i,0);
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1){
alarms.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + period,pi);
}
}
Ive tested scheduling alarms in this way in Doze and it works. They go off every 15 minutes. Check out https://commonsware.com , thats where I found this method of scheduling a repeating alarm.
Related
I used AlarmManager to set time and expect to do some work in the future. Almost case it work well without problem. But sometimes (just sometimes), the alarm not fired. It is difficult to reproduce the issue and I still do not know the reason.
I got this issue on several OS version : 4.4, 5.1, 6.0, 6.1, 7.0.
I already used WakefulBroadcastReceiver to start a service with Wakelock, but the issue still happen.
Below is my code to schedule a alarm.
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
alarmIntent.putExtra("todo_id", myTodo.getId());
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, myTodo.getId(), alarmIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(calendar.getTimeInMillis(), pendingIntent);
alarmManager.setAlarmClock(alarmClockInfo, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
public class AlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
LogUtil.debug("onReceive()");
if (null != intent.getExtras()) {
int id = intent.getIntExtra("todo_id", -1);
if (id != -1) {
Intent myIntent = new Intent(context, AlarmService.class);
myIntent.putExtra("todo_id", id);
LogUtil.debug("Receiver receive todo id: "+id );
startWakefulService(context, myIntent);
}
}
}
}
public class AlarmService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtil.debug("Service onStartCommand");
int id = intent.getIntExtra("todo_id", -1);
LogUtil.debug("Service receive todo id: " + id);
// do some stuff here
AlarmReceiver.completeWakefulIntent(intent);
return START_REDELIVER_INTENT;
}
Does anyone have the same issue like me ? And what is your solution ?
Maybe this issue come from Android SDK, they made AlarmManager work unstable.
I had the same issue , i solved this issue by doing all my logic in AlarmReceiver. I was also starting service in receiver which hold my alarm logic. But once i move my code into alarm receiver it works fine. Mine issue was i wasn't ending my service , it kept on running and causing some issue or might be other reasons but it solved my issue. You should try and let me know if this help.
here is my code in application class inside oncreate method: But I can't see any message from my app. Can anyone help me to do this?
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
public void startAlarm() {
manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
int interval = 5000;
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show();
}
And on the broadcast receiver class I have the following code
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// For our recurring task, we'll just display a message
Toast.makeText(arg0, "I'm running", Toast.LENGTH_SHORT).show();
}
}
Edited answer:
Use setInexactRepeating() instead of setRepeating(). setRepeating only takes set intervals with the shortest being INTERVAL_FIFTEEN_MINUTES. setInexactRepeating() is the only way to set a repeating interval as short as 1000ms, or 5000ms in your case.
Change:
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
to
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
If you are not getting the exact 5 second delay that you need, you will need to use a Handler. Any type of alarm with a 5 second delay will not work properly because as of Android 5.x basically all repeating alarms are inexact to save battery life.
I have modified your code to use a Handler:
startAlarm();
public void startAlarm() {
final Handler h = new Handler();
final int delay = 5000; //milliseconds
h.postDelayed(new Runnable(){
public void run(){
//do something
Intent alarmIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
sendBroadcast(alarmIntent);
h.postDelayed(this, delay);
}
}, delay);
}
That alarm method will work with your current BroadcastReceiver and do an actual 5 second delay.
I am trying to make a prototype application in which the AlarmManager needs to repeatedly(like, in every 5 seconds) perform certain operation. Its repeating whatever execution of code in onRecieve() method of my BroadcastReciever but it repeats in 1 minutes something even if its supposed to repeat in every 5 seconds. I have followed all the tutorials, I am pretty sure I am following all steps. Can somebody help to find why its repeating late every time?
AlarmRecurring.java
public class AlarmRecurring extends AppCompatActivity {
private PendingIntent pendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_alarm_recurring);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
setupButtons();
}
private void setupButtons()
{
findViewById(R.id.stopRepeating).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cancel();
}
});
findViewById(R.id.startRepeating).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startrepeating();
}
});
}
public void cancel() {
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
Toast.makeText(this, "Alarm Canceled", Toast.LENGTH_SHORT).show();
}
public void startrepeating() {
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
EditText secondsToRepeat =(EditText) findViewById(R.id.secondsToRepeat);
int repeat = Integer.parseInt(secondsToRepeat.getText().toString());
/* Repeating on every 20 minutes interval */
TimePicker tp = (TimePicker) findViewById(R.id.timePicker);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, tp.getCurrentHour());
calendar.set(Calendar.MINUTE, tp.getCurrentMinute());
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000 * repeat, pendingIntent);
Toast.makeText(this, "Repeating Alarm Started at every: " + repeat + "secs", Toast.LENGTH_SHORT).show();
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
MediaPlayer mp=null;
#Override
public void onReceive(Context context, Intent intent) {
// For our recurring task, we'll just display a message
Toast.makeText(context, "Repeating Alarm running at:" + new Date().toString(), Toast.LENGTH_SHORT).show();
mp = MediaPlayer.create(context , R.raw.short_notice);
mp.start();
}
}
Thanks :-)
As of API 22 the value of the interval will be forced up to 60000 ms if the given value is smaller.
there is some android targetsdkversion.
Beginning with API 19 (KITKAT) alarm delivery is not proper:
android OS will shift alarms in order to minimize wakeups and battery use. Te Os has given the new APIs to support applications which need strict delivery guarantees;
setWindow(int, long, long, PendingIntent);
setExact(int, long, PendingIntent);
Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
I want to display notification every morning at 9 AM from my app.
So I am using Notification Manager, Alarm Manager, BroadcastReciever and Service to make that possible.
But I have a problem, because the notification shows randomly. When I first start the app and set the time, it works OK, but later the app fires and shows notification at random time.
How I can solve that?
Here is my code:
MainActivity
#Override
protected void onStart() {
super.onStart();
setAlarm();
}
public void setAlarm(){
Calendar calendar = Calendar.getInstance();
Calendar now = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 15);
calendar.set(Calendar.MINUTE, 43);
calendar.set(Calendar.SECOND, 0);
if(calendar.getTime().after(now.getTime())) {
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmIntent = new Intent(MainActivity.this, HoroscopeNotification.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent); }
}
HoroscopNotification (BroadcastReciever)
public class HoroscopeNotification extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent arg1) {
showNotification(context);
}
private void showNotification(Context context) {
Intent service1 = new Intent(context, AlarmService.class);
context.startService(service1);
}
}
AlarmService
public class AlarmService extends Service {
private static final int NOTIFICATION_ID = 1;
private NotificationManager notificationManager;
private PendingIntent pendingIntent;
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
#SuppressWarnings("static-access")
#Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
Context context = this.getApplicationContext();
notificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this, MainActivity.class);
pendingIntent = PendingIntent.getActivity(context, 0, mIntent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentTitle("Horoskop");
builder.setContentText("Pročitajte današnji horoskop");
builder.setSmallIcon(R.drawable.ic_bik);
builder.setAutoCancel(true);
builder.setContentIntent(pendingIntent);
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
}
You'll notice in the Android SDK Reference material for the AlarmManager.setRepeating() states:
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
You need to use AlarmManager.set() on pre-APIv19 and AlarmManager.setExact() on APIv19+. When your PendingIntent is fired and you receive your Broadcast in your BroadcastReceiver.onReceive() you can set another exact alarm for the next day.
Alarm Manager Example
I think you should follow above link. From my point of view, your design pattern (setting alarm in Activity class is not a good approach). Instead (like showed in the answer above) you should set your alarm from a service. Also the code for notification goes in BroadcastReceiver class, method OnReceive (In the example it is commented "Put here YOUR code").
Good luck
I am working on an application that should download a file from the network every X seconds to check for any change, I use a service to do that, but its execution is not fixed with the delay time rate, here is my code for the service:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
checkUpdate();
return START_STICKY;
}
private Void checkUpdate() {
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
Log.i("Service", String.valueOf(++counter));
if(Helper.isNetworkAvailable(getBaseContext())) {
// download file
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
}else {
Log.e("Connection", "No connection");
}
}
}, 10000, 10000);
return null;
}
The output isn't fixed, it is supposed to run every 10 seconds, while running the service run in a random manner
How about setting up an AlarmManager within an IntentService? Much more accurate.
Intent intent = new Intent(context, YourClass.class);
PendingIntent pi = PendingIntent.getService(context, 0, intent, 0);
AlarmManager am = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), 10*1000, pi);
Make sure within YourClass.class (which is an IntentService), put your logic in the handleIntent(Intent intent), which will be called every 10 seconds by the PendingIntent sent by the AlarmManager.
P.S. Update your manifest
Hope it helps
Instead of Timer Class, use AlarmManager class. It also performs the same repeating tasks you want. AlamrManager is light weight and it runs even if your device is in sleep mode.
Also see this link Android: How to repeat a service with AlarmManager
For repetitive jobs android provides simple api, called Timer please look it. Very simple to use.
Try this :
#Override
public void onStart(Intent intent, int startId) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Log.d("Internet Available: ", ""+flag);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 10);
Intent intent1 = new Intent(this, UpdateWidgetServiceDemo.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent1, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int i;
i=15;
alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
super.onStart(intent, startId);
}
REMOVE return START_STICKY;