我想每天给用户发送离线通知。尝试了很多东西,比如:报警管理器,工作管理器,但是没有成功。通知不被触发或者只是在以后触发。
有什么办法能完成任务吗?
报警功能:
public void StartAlarm()
{
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY,23);
calendar.set(Calendar.MINUTE,59);
calendar.set(Calendar.SECOND,0);
AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
//alarmIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Log.d("LOG", String.valueOf(calendar.getTimeInMillis()));
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 156, alarmIntent, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
工作管理器代码:
public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
StartAlarm();
Log.d("In worker","yes");
return Result.success();
}
工作管理器驱动程序:
public void StartPeriodicWorker()
{
final PeriodicWorkRequest periodicWorkRequest = new
PeriodicWorkRequest.Builder(MyWorker.class,24,TimeUnit.HOURS)
.addTag("Birthday")
.build();
WorkManager.getInstance(getApplicationContext()).enqueueUniquePeriodicWork("Birthday Notifier", ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);
}
报警接收器:
公共类AlarmReceiver扩展了
private DatabaseReference myRef;
private ArrayList<String> allPeoples;
private int numberOfPeoples;
private Context ctx;
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"In alarm receiver",Toast.LENGTH_LONG).show();
ctx = context;
initPeoples();
}
public String getCurrentDate() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat mdformat = new SimpleDateFormat("d MMMM");
String strDate = mdformat.format(calendar.getTime());
return strDate;
}
private void initPeoples() {
FirebaseDatabase database = FirebaseDatabase.getInstance();
myRef = database.getReference("Users");
myRef.keepSynced(true);
myRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
allPeoples = new ArrayList<>();
for(DataSnapshot snapshot : dataSnapshot.getChildren()){
if(snapshot.getKey().equals("Teacher") || snapshot.getKey().equals("Staff")){
for(DataSnapshot faculty : snapshot.child("peoples").getChildren()){
String birthday = (String) faculty.child("DOB").getValue();
if(birthday.equals(getCurrentDate())) {
String member = birthday;
allPeoples.add(member);
}
}
}else{
for(DataSnapshot student : snapshot.child("peoples").getChildren()){
String birthday = (String) student.child("DOB").getValue();
if(birthday.equals(getCurrentDate())) {
String member = birthday;
allPeoples.add(member);
}
}
}
}
numberOfPeoples = allPeoples.size();
ShowNotification();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
public void ShowNotification()
{
String CHANNEL_ID = "Channel_1453";
String CHANNEL_NAME = "Birthday Notification";
NotificationManagerCompat manager = NotificationManagerCompat.from(ctx);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH);
manager.createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(ctx, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_stat_notify)
.setContentTitle("Birthday Reminder")
.setColor(Color.GREEN)
.setContentText("Click to see who has birthday today!")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setContentIntent(PendingIntent.getActivity(ctx, 0, new Intent(ctx, Birthday.class), PendingIntent.FLAG_UPDATE_CURRENT))
.build();
manager.notify(454, notification);
}
}
看起来你做的每件事都是对的,正如你在评论中说它在nexus S上工作,我假设你也在清单中声明了接收方。
在经历了一周同样的问题之后,结果是:
在一些带有定制操作系统的设备中,比如小米,当你把应用从最近的列表中移开时,操作系统会认为它是一个强制停止,因此所有的服务和其他东西都会被杀死。 基于问题跟踪器,目前没有办法绕过它来解决这个问题。 他们回应称,正在与OEM合作解决这一问题。
但是根据我自己的经验,如果你使用工作管理器设置你的通知,它会被延迟,但是你最终会收到它(至少大部分时间)。
但如果你希望时机准确,此刻没有办法进行。
目前唯一的解决办法就是现在给一些许可。 请访问dontkillmyapp以获取有关此手动设置的更多信息。
我可以看到一个可能的问题,在没有workmanager的情况下也可以这样做(假设设备在通知运行时连接正常)。
我建议你不要在接收器上做你的网络,而是启动一个服务(如果Android 8.0以上是前台服务),在那里做你的工作。 这是因为Android对一个接收者的时间限制比一个服务/前台服务要低得多。 因此,在我看来,你的接收器在网络请求完成之前就被杀死了,所以没有显示任何通知,这听起来似乎是合理的。
您可以在服务中显示通知,还可以安排下一个警报,因为SetExactAndAllowWhileIdle
本身并不是一个重复的警报。 所以在你的接收器中,类似于:
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, BirthdayNotifyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(service);
} else {
context.startService(service);
}
}
然后是一个可能的服务类:
public class BirthdayNotifyService extends IntentService {
public BirthdayNotifyService() {
super("BirthdayNotifyService");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//Build a simple notification to show if a foreground service is neccesary
Notification noti = notiBuilder.build();
notificationManager.notify(2021, noti);
startForeground(1, noti);
//Do your network request work here. After completed, show your birthday notification and stop the foreground service.
}
}