警报管理器无法在 android 的确切时间启动

alarm manager can't start at exact time in android

我有一个示例应用程序,我想在后台执行一些操作。 当我立即为闹钟管理器设置时间时,我的服务工作正常,但下次我设置时间时它不起作用(更改代码并在接下来的 2 分钟内再次 运行 应用程序)。

这是我的场景: 我设置了启动服务的时间和 运行 应用程序,然后单击 fab 并关闭应用程序并等待吐司。

这是我的一些 类 :

MainActivity.class

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener( view -> { startBackup();});
    }


    private void startBackup() {

        Intent serviceIntent = new Intent(getApplicationContext(), ExampleService.class);
        PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 123, serviceIntent, 0);


            Calendar cal = initCalendar(14, 36, 0);
            AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

            if (Build.VERSION.SDK_INT >= 23) {
                alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
            } else if (Build.VERSION.SDK_INT >= 19) {
                alarm.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
            } else {
                alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
            }pintent);

        }


    private Calendar initCalendar(int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);

        return calendar;
    }
}

ExampleService.class

public class ExampleService extends Service {


    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "service create service", Toast.LENGTH_LONG).show();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "Service Service you ", Toast.LENGTH_LONG).show();
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

Manifest.xml

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

    <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"
        tools:ignore="GoogleAppIndexingWarning">
        <activity
            android:name=".MainActivity"
            android:label="service test"
            android:theme="@style/AppTheme.NoActionBar">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <service android:name=".ExampleService"
            android:enabled="true"
            android:exported="true"
            />
    </application>

</manifest>

使用 setExactsetExactAndAllowWhileIdle 是正确的方法,但他们仍然需要唤醒一个 BroadcastReceiver,它需要一个唤醒锁,而 Service发布。甚至为此定义了一个有用的 class:WakefulBroadcastReceiver.

本文将有助于提供有关警报的更多信息:http://hiqes.com/android-alarm-ins-outs/

经过大量研究,我终于发现 API 26 添加了一个名为 getForeGroundService()

的待处理意图的新方法

所以代码应该是这样的:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener( view ->  startBackup());
    }


    private void startBackup() {

        Intent serviceIntent = new Intent(getApplicationContext(), ExampleService.class);


            Calendar cal = initCalendar(10, 0, 0);
            AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

            if (Build.VERSION.SDK_INT >= 26) {
                PendingIntent pintent = PendingIntent.getForegroundService(getApplicationContext(), 6546548, serviceIntent, 0);
                alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
            }else if (Build.VERSION.SDK_INT >= 23) {
                PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
                alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
            } else if (Build.VERSION.SDK_INT >= 19) {
                PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
                alarm.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis() , pintent);
            } else {
                PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
                alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis() , pintent);
            }

        }


    private Calendar initCalendar(int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);

        return calendar;
    }
}