AlarmManager setInexactRepeating无法在Android 10上运行

问题描述

自从启动android 10以来,我的应用程序中存在警报问题,我有以下代码段,我在其中用AlarmManager进行了测试,以查看是否执行了我编写的警报。 当我使用setAlarmClock时,警报会在设置的时间运行,但是当我尝试使用setInexactRepeating(或setRepeating)时,android会忽略该警报,它根本不会运行。

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val am = getSystemService(Context.ALARM_SERVICE) as AlarmManager
    val timetoTrigger = System.currentTimeMillis() + 10 * 1000
    val intervalo: Long = 60 * 1000
    val intent = Intent(this,AlarmReceiver::class.java)
    val pending = PendingIntent.getbroadcast(this,1,intent,PendingIntent.FLAG_UPDATE_CURRENT)
    
    //am.setAlarmClock(AlarmManager.AlarmClockInfo(timetoTrigger,null),pending)

    am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime() + intervalo,intervalo,pending)
  }
}

这是我的Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lb.alarm_clock_sample">

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission
    android:name="android.permission.WRITE_SETTINGS"
    android:maxsdkVersion="19" />
<uses-permission android:name="android.permission.disABLE_KEyguard" />
<uses-permission
    android:name="android.permission.READ_PHONE_STATE"
    android:maxsdkVersion="22" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".AlarmsListActivity" />

    <receiver android:name=".AlarmReceiver" />

 </application>

 </manifest>

预先感谢

编辑

根据@Crispert,使用android.permission.REQUEST_IGnorE_BATTERY_OPTIMIZATIONS可以帮助警报不被忽略。 在清单中添加以下权限:

<uses-permission android:name="android.permission.REQUEST_IGnorE_BATTERY_OPTIMIZATIONS"/>

然后在活动中创建一个函数,使用户可以选择是否希望应用程序在后台运行:

@RequiresApi(Build.VERSION_CODES.M)
private fun ignoreBatteryOptimization() {
    val intent = Intent()
    val packN = packageName
    val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
    if (!pm.isIgnoringBatteryOptimizations(packN)) {
        intent.action = Settings.ACTION_REQUEST_IGnorE_BATTERY_OPTIMIZATIONS
        intent.data = Uri.parse("package:$packN")
        startActivity(intent)
    }
}

如果用户同意忽略电池优化,则执行将在后台进行,并且警报不会出现任何问题(根据我一直在进行的测试,到目前为止我没有任何问题)。 谢谢。

解决方法

尝试添加

<uses-permission
   android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

进入应用清单,并要求用户使用授予权限 this code

总的来说,警报(通常是后台执行)在过去的android几个版本中受到故意限制,并且只有很少的应用程序可以应对。传统方法是考虑使用替代机制(有其自身的缺点)来延迟执行:JobScheduler或前台服务。 JobScheduler / jobs将消除执行的准确性和确定性(其目的是节省能源),而前台服务是侵入性的,并且能源效率更低。

如果您不依赖于Google Play进行分发,则可以尝试通过为应用程序使用较低的targetSdkVersion(可能不超过24个)来推迟不可避免的事件,以强制操作系统执行警报。但是请注意,在具有8 / Oreo和更高版本的设备上,应用程序备用存储桶和其他OEM节电机制实际上会在没有用户与您的应用程序交互的情况下根据任意条件暂停您的应用程序(因此,警报将被忽略)。 / p>

还可以考虑检查是否根本没有调用BroadcastReceiver或由于操作系统限制而无法完成其尝试执行的操作。您可能会发现触发了警报,但是应用被禁止运行代码-例如,不再允许后台代码(服务,广播)开始活动。

,

@Crispert的答案非常有趣,但是,它唯一的问题是它需要用户许可才能运行/安排警报。

我将为您提供我在其中一个应用程序中使用的解决方案,该解决方案不需要任何特定权限,因为它使用的是警报管理器方法,默认情况下会忽略任何电池优化。

在此处查看此链接: https://stackoverflow.com/a/64558739/9213980

编辑:我想补充一点,这的确不是重复的警报,但是,可以通过广播接收器的每个触发器简单,方便地重新安排它。

尽管有一些小的限制,但是就我而言,这些限制并不重要,它完全可以按照我的需要工作。您可以通过此链接在官方文档中了解更多详细信息。 https://developer.android.com/reference/kotlin/android/app/AlarmManager#setexactandallowwhileidle