Gol*_*ene 20 android alarmmanager
我需要每10分钟计划一次任务.
因为在Lollipop和更高版本setRepeating()是不精确的,我使用setExact()和(在警报发射)我在10分钟内设置新的确切警报.
private void setAlarm(long triggerTime, PendingIntent pendingIntent) {
int ALARM_TYPE = AlarmManager.ELAPSED_REALTIME_WAKEUP;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(ALARM_TYPE, triggerTime, pendingIntent);
} else {
alarmManager.set(ALARM_TYPE, triggerTime, pendingIntent);
}
}
Run Code Online (Sandbox Code Playgroud)
triggerTime 计算 SystemClock.elapsedRealtime() + 600_000;
当警报触发时,首先我计划新警报,然后我才会执行我的计划任务.
setAlarm();
mySheduledTask;
Run Code Online (Sandbox Code Playgroud)
WAKE_LOCK我的清单中有权限.
当我在Android 4上测试它时 - 它工作得很完美(偏差可能是12-15 毫秒).
但是当我在小米Redmi Note 3 Pro(5.1.1)上运行应用程序时 - 偏差可能长达15秒!
例如,我在我的日志文件中看到:第一次运行是在1467119934477(RTC时间),第二次是在1467120541683.差异是607_206毫秒,而不是600_000,因为它是计划好的!
我错过了什么?什么是模拟系统警报行为的方法(它是可以描述我的大头钉的最接近的用例)?
PS.我使用IntentServicePendingIntent = PendingIntent.getService(context, 0, myIntent, 0);
Dus*_*Dus 33
操作系统会根据您指定的时间选择警报的工作方式.因此,当手机进入"半睡眠"模式时,无需在您希望的时候使用该资源.基本上,它等待操作系统为其打开的"窗口",然后只有你想要运行的警报才会运行,这就是你遇到时间差距的原因.
这是在Marshmallow操作系统上引入的,并将继续在Nougat操作系统上,作为谷歌尝试改进设备电池的一部分.
这是事情,你有两个选择:
JobScheduler哪个更推荐,并节省电池).setExactAndAllowWhileIdle可能会导致电池问题(小心使用,太多警报对您的电池有害).此方法不重复,因此您必须声明要在pendingIntent打开的服务上运行的下一个作业.如果您选择选项2,这是开始:
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
int ALARM_TYPE = AlarmManager.RTC_WAKEUP;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
am.setExactAndAllowWhileIdle(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
am.setExact(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
else
am.set(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
Run Code Online (Sandbox Code Playgroud)
小智 11
您可以从 support.v4 调用该方法:
AlarmManagerCompat.setExact(...);
Run Code Online (Sandbox Code Playgroud)
内部实现包含按 sdk 版本进行的检查。
可能的解决方法可能是这样的:您在预期时间前约1分钟安排警报,而不是使用Handler.postDelayed来覆盖剩余时间.
在这里,您可以找到这种实现的示例.该活动只是设置了第一个警报:
public class MainActivity extends AppCompatActivity {
private static int WAIT_TIME = 60*1000; //1 minute
public static int DELAY_TIME = 10*60*1000; // delay between iterations: 10min
public static String UPDATE_TIME_KEY = "update_time_key";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setAlarm(this,(new Date().getTime())+DELAY_TIME);
}
public static void setAlarm(Context context, long delay) {
long fireDelay = delay-WAIT_TIME;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
sharedPreferences.edit().putLong(UPDATE_TIME_KEY,delay).apply();
Intent startIntent = new Intent(context, UpdateReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, startIntent,PendingIntent.FLAG_UPDATE_CURRENT );
AlarmManager alarmManager = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
int ALARM_TYPE = AlarmManager.RTC;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(ALARM_TYPE, fireDelay, pendingIntent);
} else {
alarmManager.set(ALARM_TYPE, fireDelay, pendingIntent);
}
}
}
Run Code Online (Sandbox Code Playgroud)
比接收器继续循环:
public class UpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
Log.e("RECEIVED","RECEIVED");
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
long fireTime = sharedPreferences.getLong(MainActivity.UPDATE_TIME_KEY, (new Date()).getTime());
long fireDelay =(fireTime-(new Date().getTime())>0)?fireTime-(new Date().getTime()):0;
(new Handler()).postDelayed(new Runnable() {
@Override
public void run() {
Log.e("RECEIVED","PERFORMED");
MainActivity.setAlarm(context,(new Date()).getTime()+MainActivity.DELAY_TIME);
}
},fireDelay);
}
}
Run Code Online (Sandbox Code Playgroud)
我希望它有所帮助.
回答关于系统报警的问题...
Android的股票闹钟/座钟的应用程序使用的组合setAlarmClock和setExactAndAllowWhileIdle。
以下代码用于更新通知:
final PendingIntent operation = PendingIntent.getBroadcast(context, 0,
AlarmStateManager.createIndicatorIntent(context), flags);
final AlarmClockInfo info = new AlarmClockInfo(alarmTime, viewIntent);
alarmManager.setAlarmClock(info, operation);
Run Code Online (Sandbox Code Playgroud)
同时以下代码用于调度实际警报:
if (Utils.isMOrLater()) {
// Ensure the alarm fires even if the device is dozing.
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent)
}
Run Code Online (Sandbox Code Playgroud)
setExactAndAllowWhileIdle 中
设置的 Pending 意图触发警报,而setAlarmClock 的意图则被简单地忽略。
从 API 19 (KITKAT) 开始,警报传递不准确:操作系统将转移警报以最大程度地减少唤醒和电池使用。有新的API来支持需要严格交付保证的应用程序;请参阅 setWindow(int, long, long, PendingIntent) 和 setExact(int, long, PendingIntent)。targetSdkVersion 早于 API 19 的应用程序将继续看到以前的行为,即所有警报均在请求时准确传递。
另外,在使用 setExact() 时:
警报将尽可能接近请求的触发时间。
所以仍然不能保证 setExact 一定是 Exact。
| 归档时间: |
|
| 查看次数: |
16714 次 |
| 最近记录: |