Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/183.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android-服务发送多个本地通知时出现问题_Android_Android Intent_Notifications_Android Service_Android Broadcastreceiver - Fatal编程技术网

Android-服务发送多个本地通知时出现问题

Android-服务发送多个本地通知时出现问题,android,android-intent,notifications,android-service,android-broadcastreceiver,Android,Android Intent,Notifications,Android Service,Android Broadcastreceiver,我继承了一个Android应用程序的代码库,我面临着一个本地通知的特别问题 这样做的目的是为将来计划的每个事件发送通知,同时考虑到用户希望在事件发生前多少分钟收到通知的提醒首选项 一切正常,除了在第一次抛出通知后,如果用户在事件开始之前打开应用程序,则会再次抛出通知。每次在(事件开始日期-提醒)和事件开始日期之间打开应用程序时都会发生这种情况 我已经看了一眼,也没有运气。 我已经读到,使用服务可能会导致这个问题,一些人建议删除它,但我认为这是必要的,因为在应用程序关闭时也必须抛出通知 目前该守则

我继承了一个Android应用程序的代码库,我面临着一个本地通知的特别问题

这样做的目的是为将来计划的每个事件发送通知,同时考虑到用户希望在事件发生前多少分钟收到通知的提醒首选项

一切正常,除了在第一次抛出通知后,如果用户在事件开始之前打开应用程序,则会再次抛出通知。每次在(事件开始日期-提醒)和事件开始日期之间打开应用程序时都会发生这种情况

我已经看了一眼,也没有运气。 我已经读到,使用服务可能会导致这个问题,一些人建议删除它,但我认为这是必要的,因为在应用程序关闭时也必须抛出通知

目前该守则的结构如下:

编辑-更新选项卡活动的描述

在TabBarActivity中,我有一个调度AlarmManager的方法scheduleTravelNotification。 每次在本地数据库上添加新事件时,或者如果已更新现有事件,都会执行此方法。 TabBarActivity在onCreate和onResume方法中运行此方法。 TabBarActivity也是notification-onclick事件的目标

private static void scheduleTravelNotification(Context context, RouteItem routeItem) {

    long currentTime = System.currentTimeMillis();
    int alarmTimeBefore = routeItem.getAlarmTimeBefore();
    long alarmTime = routeItem.getStartTime() - (alarmTimeBefore * 1000 * 60);

    if(alarmTimeBefore < 0){
        return;
    }

    if(alarmTime < currentTime){
        return;
    }

    Intent actionOnClickIntent = new Intent(context, TravelNotificationReceiver.class);
    PendingIntent travelServiceIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis(), actionOnClickIntent, PendingIntent.FLAG_ONE_SHOT);

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(alarmTime);
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), travelServiceIntent);

    Log.e("NEXT ALARM", "Time: " + String.valueOf(calendar.getTimeInMillis()));
}
TravelNotificationService.java扩展了NotificationService.java设置为type=“Travel”、flags=0、title=“something”和text=“something other”

编辑-以下是NotificationHelper.buildNotification的代码

    public static Notification buildNotification(Context context, String title, String text, PendingIntent pendingIntent) {

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);

        builder.setAutoCancel(true);
        builder.setContentText(text);
        builder.setContentTitle(title);
        builder.setContentIntent(pendingIntent);
        builder.setSmallIcon(R.mipmap.launcher);
        builder.setCategory(Notification.CATEGORY_MESSAGE);
        builder.setVisibility(Notification.VISIBILITY_PUBLIC);

        return builder.build();
    }
谢谢你的回答


编辑我也看到了,但没有公认的答案,而post建议了一些我认为已经使用if(alarmTime 您有一些处理此问题的选项

一种是创建一个布尔标志作为服务的属性,默认为false,并在发送通知之前进行检查。如果为false,则发送通知并将其设置为true;如果为true,则不发送通知


另一种方法是检查服务是否已经在运行,如果已经在运行,那么首先不要发送服务启动命令。在任何地方这样做都会很乏味,因此如果你采用这种方法,你可能会想在你的服务类中创建一个静态方法,检查服务是否正在运行,如果没有,则启动它,并调用该方法,而不是显式启动服务。

这可能不是你真正的问题,但乍一看,您正在onStartCommand()中发送通知,该通知本身可以在服务生命周期内多次运行——例如,如果您在一次创建活动时“盲目”发出服务启动命令,则每次(重新)创建活动时都会发生

您有一些处理此问题的选项

一种是创建一个布尔标志作为服务的属性,默认为false,并在发送通知之前进行检查。如果为false,则发送通知并将其设置为true;如果为true,则不发送通知


另一种方法是检查服务是否已经在运行,如果已经在运行,那么首先不要发送服务启动命令。这在任何地方都可能很繁琐,因此如果您采用这种方法,您可能希望在服务类中创建一个静态方法,检查服务是否正在运行,如果没有,则启动它,并调用它,而不是显式启动服务。

与user3137702答案类似,您可以简单地使用一个静态布尔值APPISINFORGROUND,它在每次点击发送通知方法时都会被检查,并从您的应用程序/活动代码中进行管理

正如用户所说,由于应用程序/服务生命周期的原因,您的onStartCommand方法可能在奇数时间被调用


或者,检查您的接收器是否没有从代码的其他地方被调用。

与user3137702答案类似,您可以简单地获得一个静态布尔值APPISINFORGROUND,它在每次点击发送通知方法时被检查,并从您的应用程序/活动代码进行管理

正如用户所说,由于应用程序/服务生命周期的原因,您的onStartCommand方法可能在奇数时间被调用


或者,检查您的接收器是否未在代码的其他地方被调用。

可能是您的NotificationHelper类导致了问题。请共享该类的代码

一种想法可能是通知未设置为自动取消,请检查通知生成器中是否包含setAutoCancel()方法

Notification notification = new Notification.Builder(this).setAutoCancel(true).build();

可能是您的NotificationHelper类引起了问题。请共享该类的代码

一种想法可能是通知未设置为自动取消,请检查通知生成器中是否包含setAutoCancel()方法

Notification notification = new Notification.Builder(this).setAutoCancel(true).build();

我已经找到了一种方法让它发挥作用,我在这里发布这篇文章,因为这似乎是许多人使用和文章中建议的方法的一个问题。经过几个月的测试,我可以说我对我找到的解决方案非常满意。 关键是避免使用服务,并依赖AlarmScheduler和接收器

1) 通过添加以下行在清单中注册收件人:

<receiver android:name="<your path to>.AlarmReceiver" />
3) 定义报警接收器

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // Find object details by using objectId form intent extras (I use Realm but it can be your SQL db)
        MyObject myObject = RealmManager.MyObjectDealer.getObjectById(intent.getStringExtra("OBJECT_ID"), context);

        // Prepare notification title and text
        String title = myObject.getSubject();
        String text = myObject.getFullContent();

        // Prepare notification intent
        // HomeActivity is the class that will be opened when user clicks on notification
        Intent intentAction = new Intent(context, HomeActivity.class);

        // Same procedure for pendingNotification as in method of step2
        PendingIntent pendingNotificationIntent = PendingIntent.getActivity(context, myObject.getId(), intentAction, PendingIntent.FLAG_UPDATE_CURRENT);

        // Send notification (I have a static method in NotificationHelper)
        NotificationHelper.createAndSendNotification(context, title, text, pendingNotificationIntent);
    }
}
4) 定义NotificationHelper

public class NotificationHelper {

    public static void createAndSendNotification(Context context, String title, String text, PendingIntent pendingNotificationIntent) {

        // Get notification system service
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);

        // Build notification defining each property like sound, icon and so on
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context);
        notificationBuilder.setContentTitle(title);
        notificationBuilder.setContentText(text);
        notificationBuilder.setSmallIcon(R.drawable.ic_done);
        notificationBuilder.setCategory(Notification.CATEGORY_MESSAGE);
        notificationBuilder.setVisibility(Notification.VISIBILITY_PUBLIC);
        notificationBuilder.setAutoCancel(true);
        notificationBuilder.setContentIntent(pendingNotificationIntent);
        notificationBuilder.setDefaults(Notification.DEFAULT_SOUND);
        notificationManager.notify(1001, notificationBuilder.build());
    }
}
在这一点上,它应该工作和schedu
public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // Find object details by using objectId form intent extras (I use Realm but it can be your SQL db)
        MyObject myObject = RealmManager.MyObjectDealer.getObjectById(intent.getStringExtra("OBJECT_ID"), context);

        // Prepare notification title and text
        String title = myObject.getSubject();
        String text = myObject.getFullContent();

        // Prepare notification intent
        // HomeActivity is the class that will be opened when user clicks on notification
        Intent intentAction = new Intent(context, HomeActivity.class);

        // Same procedure for pendingNotification as in method of step2
        PendingIntent pendingNotificationIntent = PendingIntent.getActivity(context, myObject.getId(), intentAction, PendingIntent.FLAG_UPDATE_CURRENT);

        // Send notification (I have a static method in NotificationHelper)
        NotificationHelper.createAndSendNotification(context, title, text, pendingNotificationIntent);
    }
}
public class NotificationHelper {

    public static void createAndSendNotification(Context context, String title, String text, PendingIntent pendingNotificationIntent) {

        // Get notification system service
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);

        // Build notification defining each property like sound, icon and so on
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context);
        notificationBuilder.setContentTitle(title);
        notificationBuilder.setContentText(text);
        notificationBuilder.setSmallIcon(R.drawable.ic_done);
        notificationBuilder.setCategory(Notification.CATEGORY_MESSAGE);
        notificationBuilder.setVisibility(Notification.VISIBILITY_PUBLIC);
        notificationBuilder.setAutoCancel(true);
        notificationBuilder.setContentIntent(pendingNotificationIntent);
        notificationBuilder.setDefaults(Notification.DEFAULT_SOUND);
        notificationManager.notify(1001, notificationBuilder.build());
    }
}
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name="<your path to>.BootReceiver" >
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>
public class BootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // Do something very similar to AlarmReceiver but this time (at least in my case) since you have no source of intents loop through collection of items to understand if you need to schedule an alarm or not
        // The code is pretty similar to step 3 but repeated in a loop
    }
}