如何在Android 10中显示每日离线通知? [英] How to show daily offline notifications in Android 10?

查看:125
本文介绍了如何在Android 10中显示每日离线通知?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想每天向用户发送脱机通知.尝试了很多事情,例如:警报管理器,工作管理器,但是没有运气.通知没有触发,或者只是稍后触发.

有什么方法可以完成工作吗?

警报功能:

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扩展了BroadcastReceiver {

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);
}

}

解决方案

我可以看到一个可能的问题,并且可以在没有工作管理器的情况下做到这一点(假设通知运行时设备连接正常)./p>

建议您不要启动接收器中的网络,而建议启动服务(如果是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) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //Build a simple notification to show if a foreground service is neccesary
            Notification noti = notiBuilder.build();
            startForeground(1, noti);
        }

        //Do your network request work here. After completed, show your birthday notification and stop the foreground service.
    }
}

要停止服务,请在显示生日通知后立即使用以下命令:

stopForeground(true);
stopSelf();

更新:我在手机(小米Redmi Note 8 plus)上使用了此方法,该方法可以工作几次,但随后停止工作.它在股票android上工作得很好,但在所有设备上都没有.因此,我仍然会说这不是在特定时间发送通知的可靠解决方案.

I want to send offline notifications to users daily.Tried many things like: Alarm manager,Work manager but no luck.The notifications are not triggered or they just trigger at later.

Any way to get the job done?

Alarm function:

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);
        }

Work manager code:

 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();
}

Work manager driver:

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);

}

Alarm Receiver:

public class AlarmReceiver extends BroadcastReceiver {

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);
}

}

解决方案

I can see one possible issue, and it's possible to do this without the workmanager (assuming the device has a healthy connection at the time the notification runs).

Instead of doing your network in the receiver itself, I suggest starting a service (foreground service if above Android 8.0), and doing your work there. This is because android's time limit for a receiver is much lower than a service/foreground service. So to me, it sounds plausible that your receiver is killed before the network request completes, and so no notification is shown.

You can show the notification in the service, and also schedule the next alarm since setExactAndAllowWhileIdle isn't a repetitive alarm on it's own. So in your receiver, something like:

@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);
        }
}

Then a possible service class:

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) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //Build a simple notification to show if a foreground service is neccesary
            Notification noti = notiBuilder.build();
            startForeground(1, noti);
        }

        //Do your network request work here. After completed, show your birthday notification and stop the foreground service.
    }
}

To stop the service, right AFTER you display your notification for birthdays, use the following:

stopForeground(true);
stopSelf();

UPDATE: I used this method on my phone (Xiaomi Redmi Note 8 plus), it worked a few times but then stopped working. It works perfectly fine on stock android, but not on all devices. Therefore I would still say this is not a reliable solution to send notification on specific times.

这篇关于如何在Android 10中显示每日离线通知?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆