AlarmManager setInexactRepeating 在 Android 10 上不工作

AlarmManager setInexactRepeating not working on Android 10

自从 android 10 启动后,我的应用程序中出现了警报问题,我有以下代码片段,我在其中使用 AlarmManager 进行测试以查看我编写的警报是否已执行。 当我使用setAlarmClock时,在设置的时间报警运行s,但是当我尝试使用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"/>

然后在 activity 中创建一个函数,让用户选择是否希望应用程序在后台运行:

@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)来尝试强制 OS 来执行你的警报。但是请注意,在具有 8/Oreo 和更新版本的设备上,应用程序待机桶和其他 OEM 电池节省机制实际上会在没有用户与您的应用程序交互的情况下根据任意标准暂停您的应用程序(因此警报将被忽略)。

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

@Crispert 的回答很有趣,但是唯一的问题是它需要用户的许可才能run/schedule报警。

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

在此处查看 link:

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

虽然有一些小的限制,但在我的情况下,这些限制并不重要,它完全符合我的需要。您可以通过此 link 在官方文档中阅读更多详细信息 https://developer.android.com/reference/kotlin/android/app/AlarmManager#setexactandallowwhileidle