如何在应用程序关闭时每小时触发一次闹钟



我有一个生日应用程序,需要每天检查一次本地共享首选项数据,以查看某人的生日是否是那一天。

截至目前,我正在尝试做一些简单的事情:每分钟发送一次测试通知,即使我单击后退按钮,向上滑动以关闭应用程序,打开另一个应用程序,关闭手机(不关闭)等。

如果我能让这个大约每分钟提醒工作一次,我可以调整它以显示来自 SharedPreferences 的数据,这没什么大不了的。但是有一个问题:

警报管理器根本没有按照他们在文档中所说的方式工作。

我为我的警报管理器使用 setInexactRepeating,并触发一个名为"ReminderAlarm"的类,然后启动一个创建通知通道并构建测试通知的服务。问题是当我退出应用程序时,根本不会显示任何通知。但是,只要我打开应用程序,他们就会打开。因此,由于某种原因,除非应用程序打开,否则警报管理器不会触发。(我也用 Log.d 尝试过这个,它也只有在应用程序打开时才打印到日志)

这是设置重复警报的原因:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter);
ToggleButton toggle = (ToggleButton) findViewById(R.id.toggleButton);
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
setAlarm();
} else {
cancelAlarm();
}
}
});
}
private void setAlarm() {
alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, ReminderAlarm.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), 100, pendingIntent);
}
private void cancelAlarm() {
//alarmManager.cancel(pendingIntent);
}

这是警报接收器:(它在清单中定义为接收器)

public class ReminderAlarm extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, ReminderBuilderService.class);
context.startService(i);
}
}

这是提醒生成器服务:(它在清单中定义为服务)

public class ReminderBuilderService extends Service {
public final String CHANNEL_ID = "MainChannel";
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
buildNotification();
return super.onStartCommand(intent, flags, startId);
}
private void createNotificationChannel() {
String name = "Birthday Notifications";
String description = "Reminds you when your friends birthday approaches";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
private void buildNotification() {
Context context = getApplicationContext();
Intent openTap = new Intent(context, EnterActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, openTap, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
builder.setSmallIcon(R.drawable.pix_cake);
builder.setContentTitle("TestNotification");
builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText("TestText"));
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(0, builder.build());
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

通知应该每分钟出现一次(我知道setInexRepeating不允许精确的重复计时),但它只在应用程序打开时显示

最后,这里是 Android Manifest xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myfirstapp">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SET_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:icon="@mipmap/main_icon"
android:label="@string/app_name"
android:roundIcon="@mipmap/main_icon_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver android:name=".ReminderAlarm"/>
<activity android:name=".ListOfDaysActivity" />
<activity android:name=".MainActivity" />
<activity android:name=".EnterActivity"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".ReminderAlarm"/>
<service android:name=".ReminderBuilderService"/>
</application>
</manifest>

我错过了什么吗?

您可以使用JobSchedulerAlarmManager来实现您想要的结果。但是您应该使用的是根据Android版本WorkManager两者的抽象。

WorkManager是高度可配置的,允许您创建PeriodicWorkRequestOneTimeWorkRequest保证成功。PeriodicWorkRequest将在您计划工作时以及在计时器中指定时触发。即使应用程序已关闭或后台运行,它也将在后台执行。如果你不希望你的任务立即执行,你可以使用PWR(PeriodicWorkRequest)和一个FlexInterval。有关详细信息,请参阅下面的文档。

工作管理器文档

工作管理器体系结构

工作管理器代码实验室

例如,我创建了两个 PeriodicWorkRequests,用于刷新服务并通过续订令牌使用户始终保持登录状态。当用户进行身份验证时,将创建PeriodicWorkRequest。就我而言,我不需要立即触发它,因为他们刚刚收到并缓存了这些信息,所以我使用了 FlexInterval。当应用在后台或关闭时,辅助角色继续每 12 小时刷新一次服务,每 6 小时刷新一次令牌。它就像一个魅力。

下面是一个示例:

构建工作:

override fun beginWork() {
val periodicWorkRequest = PeriodicWorkRequest.Builder(
MyWorker::class.java,
REPEAT_INTERVAL, TimeUnit.MINUTES, // How often work should repeat
// Flex not required.
FLEX_INTERVAL, TimeUnit.MINUTES) // Limits execution into a time window
.setConstraints(
Constraints.Builder().setRequiredNetworkType(
NetworkType.CONNECTED).build())
.addTag(MY_WORKER_TAG)
.build()
WorkManager.getInstance().enqueueUniquePeriodicWork(
MY_UNIQUE_WORK,
ExistingPeriodicWorkPolicy.KEEP,
periodicLoginRequest)

工人:

class MyWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
// DO WORK HERE
Result.success()
} else {
// HANDLE FAILURE HERE
Result.failure()
}

以上是一个简单的实现,但它应该给你一个大致的想法。

最新更新