通知每天都在同一时间(Notification every day at the same time

2019-10-21 06:07发布

我想要的是

我希望每天都在同一时间的通知。
我已经读了一些文章和教程/例子,但它无法正常工作。

第1版

错误:Android的进程/服务RE /启动后每隔〜3分钟死亡

11-07 07:33:05.725  4611  6121 I ActivityManager: Process at.htl3r.appmosphere (pid 5238) has died.
11-07 07:33:05.725  4611  6121 W ActivityManager: Scheduling restart of crashed service at.htl3r.appmosphere/.notify.NotifyService in 14648ms
11-07 07:33:20.400  4611  4632 I ActivityManager: Start proc at.htl3r.appmosphere for service at.htl3r.appmosphere/.notify.NotifyService: pid=5463 uid=10096 gids={50096}

---

11-07 07:33:41.580  4611  4623 I ActivityManager: Process at.htl3r.appmosphere (pid 5463) has died.
11-07 07:33:41.580  4611  4623 W ActivityManager: Scheduling restart of crashed service at.htl3r.appmosphere/.notify.NotifyService in 73293ms
11-07 07:33:44.310  4611  5385 F ProcessStats: Starting service ServiceState{43760cf0 at.htl3r.appmosphere.notify.NotifyService pkg=at.htl3r.appmosphere proc=43760cf0} without owner

这是两个方法(有和没有在最后一行所有者)
此错误是只对我的S3等等极值,我的N7(2013),它是一个好一点

每次重新启动后,我收到了通知。 (只是一个想法:如果我删除它,可能性较高,使系统崩溃。)

恼人的有点收到通知每3分钟^ - ^

编码

版本1 -与服务

更新1

拉里·席费尔更新的代码告诉
新的完整日志

更新2

NotifyManager
请参阅下面的最新版本
从这个更新版本

NotifyReceiver

public class NotifyReceiver extends BroadcastReceiver {
    private static final String TAG = "NotifyReceiver";

    public static final int ID_NEWHINTAVAILABLE = 1;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive");
        SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(context);

        NotificationManager mNM = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        Intent i = new Intent(context.getApplicationContext(), MainActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 0, i, 0);

        Notification.Builder mNotifyBuilder = new Notification.Builder(context);

        mNotifyBuilder.setSmallIcon(R.drawable.ic_stat_name);
        mNotifyBuilder.setContentTitle(context.getString(R.string.app_name));
        mNotifyBuilder.setContentText(context.getString(R.string.notification_contenttext));
        mNotifyBuilder.setContentIntent(pIntent);

        mNotifyBuilder.setAutoCancel(true);

        // has to have an icon - now the app icon
        // auto cancel after click: in main use cancel(int id);
        // mNotifyBuilder.addAction(R.drawable.ic_stat_name, getString(R.string.notification_action), pIntent);

        // mNotifyBuilder.setTicker(getString(R.string.app_name));
        // mNotifyBuilder.setTicker(getString(R.string.app_name)+" "+getString(R.string.notification_contenttext));

        // mNotifyBuilder.setWhen(System.currentTimeMillis());

        // mNotifyBuilder.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
        // http://stackoverflow.com/questions/2724871/how-to-bring-up-list-of-available-notification-sounds-on-android
        String sound = spref.getString(SettingsFragment.pref_notify_sound, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION).toString());
        mNotifyBuilder.setSound(Uri.parse(sound));

        if (spref.getBoolean(SettingsFragment.pref_notify_vibrate, true)) {
            // mNotifyBuilder.setVibrate(new long[] { 0, 1000 });
            mNotifyBuilder.setDefaults(Notification.DEFAULT_VIBRATE);
        }
        if (spref.getBoolean(SettingsFragment.pref_notify_light, true)) {
            mNotifyBuilder.setLights(Color.GREEN, 3000, 3000);
        }

        Notification mNotify = mNotifyBuilder.build();

        mNM.notify(ID_NEWHINTAVAILABLE, mNotify);

        NotifyManager.startAlarm(context, true);
        // wenn aktiviert: ausgeführt & neu gestartet
        // bei Deaktiviertung: abgebrochen - demnach kein Neustart
    }
}

更新3

自动启动工作..
但现在,它死也没有在这个代码更改; 只有上面的代码

<receiver android:name="at.htl3r.appmosphere.notify.Autostart" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
</receiver>

Autostart.java

public class Autostart extends BroadcastReceiver {
    private static final String TAG = "autostart";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (NotifyManager.isNotificationEnabled(context)) {
            NotifyManager.startAlarm(context);
            Log.i(TAG, "started");
        }
    }
}

目录下载
S3 -全
N7

12-14 23:15:19.227  1452  1679 I ActivityManager: Start proc at.htl3r.appmosphere for broadcast at.htl3r.appmosphere/.notify.Autostart: pid=5837 uid=10391 gids={50391, 3003}
12-14 23:15:42.300  1452  4109 I ActivityManager: Killing 5837:at.htl3r.appmosphere/u0a391 (adj 15): empty #17
12-15 06:43:47.501 18799 18819 D JsonParser: at.htl3r.appmosphere: publishState=6
12-15 06:43:47.501 18799 18819 D JsonParser: Skipping app 0 with state != 1: package name=at.htl3r.appmosphere: state=6

更新4

NotifyManager

public class NotifyManager {
    private static final String TAG = "NotifyManager";

    /**
     * {@link #startAlarm(Context, boolean)}<br>
     * default: restart: true
     * 
     * @param context Context of activity
     * @return alarm started: true<br>
     *         is running: false
     */
    public static boolean startAlarm(Context context) {
        return startAlarm(context, false);
    }

    /**
     * @param context Context of activity
     * @param restart start the alarm even when already running
     * @return true if started | false if running and not started
     */
    public static boolean startAlarm(Context context, boolean restart) {// todo restart alarm on settings change
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(context);

        String time = spref.getString(SettingsFragment.pref_notify_time, TimePreference.notify_default);
        int hour = Integer.parseInt(time.split("\\:")[0]);
        int minute = Integer.parseInt(time.split("\\:")[1]);

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        // alternative: HOUR and AM_PM
        if (calendar.getTimeInMillis() < Calendar.getInstance().getTimeInMillis()) {
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }

        // String time = new SimpleDateFormat("hh:mm", Locale.getDefault()).format(calendar.getTime());

        if (!isAlarmRunning(context) || restart) {
            alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), getPendingIntent(context));
            Log.d(TAG, "Start Alarm at " + time);
            // Toast.makeText(context, "Start Alarm at " + time, Toast.LENGTH_LONG).show();
            return true;
        }
        Log.d(TAG, "Service already running");
        return false;
    }

    /**
     * @param context Context of activity
     * @return true if running and canceled
     */
    public static boolean cancelAlarm(Context context) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

        if (isAlarmRunning(context)) {
            alarmManager.cancel(getPendingIntent(context));
            Log.d(TAG, "Cancel Alarm");
            NotifyManager.isAlarmRunning(context);
            // Toast.makeText(context, "Cancel Alarm from " + time, Toast.LENGTH_LONG).show();
            return true;
        }
        Log.d(TAG, "Service already canceled");
        return false;
    }

    /**
     * @param context Context of activity
     * @return if alarm is running
     */
    public static boolean isAlarmRunning(Context context) {
        Intent intent_service = new Intent(context, NotifyReceiver.class);
        Log.d(TAG, "isAlarmRunning:" + (PendingIntent.getBroadcast(context, 0, intent_service, PendingIntent.FLAG_NO_CREATE) != null));
        return (PendingIntent.getBroadcast(context, 0, intent_service, PendingIntent.FLAG_NO_CREATE) != null);
    }

    /**
     * @param context Context of activity
     * @return PendingIntent
     */
    public static PendingIntent getPendingIntent(Context context) {
        Intent intent = new Intent(context, NotifyReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);

        // If it exists return it
        if (pi != null)
            return pi;

        // It doesn't exist, make it (last parameter to 0 for reusable):
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
    }

    /**
     * @return yyMMdd
     */
    public static String getCurrentTimeStamp() {
        SimpleDateFormat sdfDate = new SimpleDateFormat("yyMMdd", Locale.getDefault());
        Date now = new Date();
        String strDate = sdfDate.format(now);
        return strDate;
    }

    /**
     * @param context Context of the activity
     * @return if notification is enabled or not
     */
    public static boolean isNotificationEnabled(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SettingsFragment.pref_notify, true);
    }
}

Answer 1:

A点:服务代码缺少的重要组成部分

在上面的代码中,服务具有onCreateonDestroy ,是创建和销毁的服务时,这将被触发。 但是,如果一个服务被触发,它已经在运行,那么就不会通过去onCreate 。 它将,但是,经过onstartCommandonStart预安卓2.0)。 你的代码的实际结构应该是:

onCreate() {
    // Stuff you only do when this class is instantiated the first time
    // and don't need to do if it is called (started in android terminology)
    // thereafter
}

// The next two are >=2.0 and then <2.0
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
      startHandleIntent(intent);
      return START_STICKY; // If you want the service to hang around
  }

@Override
public void onStart(Intent intent, int startId) {
  startHandleIntent(intent);        
}

void startHandleIntent(Intent intent) {
    // Do things that shiould happen every time here
    // eg. in your case, the notification
}

B点:这是不是真的有什么服务是专为

你不能靠挂在那么久的服务。 未激活的服务经常会被移除,以腾出空间用于其他东西。 鉴于该服务确实非常少,它可能会更好地使用广播接收器,这是对的事情,需要触发偶尔专门设计,但并不真的需要在那里,否则。 所以:

  1. 使用BroadcastRecevier赶上触发并发出通知。 事情是这样的:

     class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // Issue the notidfication <...> // Reissue a request for a future alarm call here if needed <...> } } 

    请记住,设置它在清单中,以接收广播:

     <application> ... other stuff ... <receiver android:name=".MyBroadcastReceiver" android:enabled="true"> <intent-filter> <action android:name="com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION"/> </intent-filter> </receiver> </application> 
  2. 要触发的是,你需要一个意图将触发广播:

     Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION"); context.sendBroadcast(intent); 

    如果你设置它通过一个的PendingIntent后来打电话(如果你想要一个可重用的改变最终标志零PendingIntent的重复事件):

     Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION"); PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT) 

    如果以后你想改变或取消服用点,或者如果你只需要知道,如果意图之前从系统的观点存在:

     Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION"); PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE); if (pi != null) { // It exists. If you want then to cancel the alarm that triggers it: alarmManager.cancel(pi); } else { // It doesn't exist. If you need to create a reusable PendingIntent: PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0); } 

    就个人而言,我会用这种方法,而不是initializePendingIntent ,即:

     public static PendingIntent getPendingIntent() { Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION"); PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE); // If it exists return it if (pi != null) return pi; // It doesn't exist, make it (last parameter to 0 for reusable): return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT); } 
  3. 使用SharedPreferences(因为你已经这样做)来跟踪是怎么回事(报警的时间)

我更倾向于将仅创建了一个投篮的意图为下一个闹钟响铃一对射报警。 如果它的变化,删除此报警,并创建一个新的。 当它触发,箱子一个新的。 这样,您减少的东西,有活路的时间长度的数量。



Answer 2:

检查logcat的一个堆栈跟踪。 这将是您所提供的活动管理服务条目之前。 该行看起来可疑对我来说,特别是setAction ,因为它并没有提供给该图标上的正确的资源价值:

mNotifyBuilder.setContentTitle(getString(R.string.app_name)).setContentText(getString(R.string.notification_contenttext)).setContentIntent(pIntent).addAction(0, getString(R.string.notification_action), pIntent).setAutoCancel(true)


文章来源: Notification every day at the same time