首页 > 解决方案 > 用于长期通知的 AlarmManager - 它有效

问题描述

跳到我的回答下面

我见过类似的问题,但没有合适或正确的答案,有些甚至是矛盾的。

问题很简单:alarmManager 不能长时间(超过几个小时)工作吗?

我有一个包含消息数组的应用程序。在第一次运行时,每个 msg 都会获得一个个人计时(Calendar obj),应用程序为每个 msg 设置一个 alarmManager,并将所有信息保存在 sharedPreference 中。下面的代码(我当然只复制了相关的)工作正常,即使我重新启动设备(感谢 sharedPref)几个小时然后停止发送通知。

如果我将整个味精时间设置为短期(假设:10 次味精,每 5 分钟 1 次)效果很好并且它们都发送了。但如果我每小时安排一次,它只在前 2-3 小时有效。

我已经看到一些答案说 alarmManager 不适合长期使用,而其他答案说它是完美的服务:( 有人可以给我一个专业的答案吗?

我也尝试了 alarmManager.setAlarmClock () 和 setExactAndAllowWhileIdle () 但结果相同。

标签: androidbroadcastreceiveralarmmanager

解决方案


好的,经过长时间的挖掘,我想我明白了。它现在可以工作,重新启动后,通知又回来了。

我在这里发布我的代码,首先是给任何寻找解决方案的人,其次——我想听听你的意见——如果我做得对等等。Tnx

msg.activity

private void addAlerts (MyMsg myMsg) {
        MyReceiver rc = new MyReceiver ();

        for (int i = 1; i < myMsg.totalMsgNum; i++)
            rc.setSingleNotifications (this, myMsg.msg[i]);
}

MyReciever.java

public class MyReceiver extends BroadcastReceiver {

    final String CHANNEL_ID = "777";
    SharedPreferences pref;
    SharedPreferences.Editor editor;


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

            // get the relevant content
            pref = context.getSharedPreferences ("SAVED_FILE", Context.MODE_PRIVATE);

            int atMsgNum = pref.getInt ("CURRENT", 1);

            String json = pref.getString ("USER_OBJ", "");
            Gson gson = new Gson ();
            User user = gson.fromJson (json, User.class);

            String titleStr = user.msg[atMsgNum].title;
            String contentStr = user.msg[atMsgNum].msg;


            // update current msg num
            editor = pref.edit ();
            editor.putInt ("CURRENT", atMsgNum + 1);
            editor.commit ();


            // intent for showing the msg activity
            intent.setClass (context, OnPressNotificationActivity.class);
            intent.putExtra ("ID", atMsgNum);
            intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);


            // notification
            createNotificationChannel (context);

            TaskStackBuilder stackBuilder = TaskStackBuilder.create (context);
            stackBuilder.addNextIntentWithParentStack (intent);

            PendingIntent pendingIntent = stackBuilder.getPendingIntent (atMsgNum, 0);

            NotificationCompat.Builder builder;

            builder = new NotificationCompat.Builder (context, CHANNEL_ID)
                    .setSmallIcon (R.drawable.single_pics_logo)
                    .setContentTitle (titleStr)
                    .setContentText (contentStr)
                    .setStyle (new NotificationCompat.BigTextStyle ()
                            .bigText (contentStr))
                    .setPriority (NotificationCompat.PRIORITY_HIGH)
                    .setContentIntent (pendingIntent)
                    .setAutoCancel (true)
                    .setBadgeIconType (NotificationCompat.BADGE_ICON_SMALL)
                    .setVisibility (NotificationCompat.VISIBILITY_PUBLIC); 

            NotificationManagerCompat notificationManager = NotificationManagerCompat.from (context);
            notificationManager.notify (atMsgNum, builder.build ());
        }



    public void setSingleNotifications (Context context, Msg msg) {


        Intent intent = new Intent (context, MyReceiver.class);

        PendingIntent alarmIntent = PendingIntent.getBroadcast (context, msg.num, intent, PendingIntent.FLAG_UPDATE_CURRENT);


        Calendar calendar = Calendar.getInstance ();
        calendar.setTimeInMillis (System.currentTimeMillis ());
        calendar.set (Calendar.YEAR, msg.calendar.get (Calendar.YEAR));
        calendar.set (Calendar.MONTH, msg.calendar.get (Calendar.MONTH));
        calendar.set (Calendar.DAY_OF_MONTH, msg.calendar.get (Calendar.DAY_OF_MONTH));
        calendar.set (Calendar.HOUR_OF_DAY, msg.calendar.get (Calendar.HOUR_OF_DAY));
        calendar.set (Calendar.MINUTE, msg.calendar.get (Calendar.MINUTE));
        calendar.set (Calendar.SECOND, msg.calendar.get (Calendar.SECOND));
        calendar.add (Calendar.SECOND, 2);

        AlarmManager alarmManager = (AlarmManager) context.getSystemService (ALARM_SERVICE);


       AlarmManager.AlarmClockInfo almInfo = new AlarmManager.AlarmClockInfo (calendar.getTimeInMillis (), null);

        alarmManager.setAlarmClock (almInfo, alarmIntent);
    }



    private void createNotificationChannel (Context context) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        {
            CharSequence name = "myMsgApp";
            String description = "daily alert";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel channel = new NotificationChannel (CHANNEL_ID, name, importance);
            channel.setDescription (description);

            NotificationManager notificationManager = context.getSystemService (NotificationManager.class);
            notificationManager.createNotificationChannel (channel);
        }
    }
}

RestartReceiver.java // 用于重启

public class RestartReceiver extends BroadcastReceiver {


    @Override
    public void onReceive (Context context, Intent intent) { // restarts alarms only when device restart

        if (intent.getAction ().equals ("android.intent.action.BOOT_COMPLETED")) {

            SharedPreferences sharedPreferences = context.getSharedPreferences ("SAVED_FILE", context.MODE_PRIVATE);
            String json = sharedPreferences.getString ("USER_OBJ", "");

            Intent in = new Intent (context, RestartService.class);
            in.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // ??
            in.putExtra ("JSON_STRING", json);
            in.putExtra ("CURRENT", sharedPreferences.getInt ("CURRENT", 1));


            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                context.startForegroundService (in);
            else
                context.startService (in);
        }
    }
}

重启服务.java

public class RestartService extends IntentService {


    public RestartService () {
        super ("RestartService");
    }

    public RestartService (String name) {
        super (name);
    }

    @Override
    protected void onHandleIntent (@Nullable Intent intent) {

        String json = intent.getExtras ().getString ("JSON_STRING", "");
        Gson gson = new Gson ();
        User user = gson.fromJson (json, User.class);
        user.atMsgNum = intent.getExtras ().getInt ("CURRENT", 1);

        MyReceiver rc = new MyReceiver ();

        for (int i = user.atMsgNum; i < user.totalMsgNum; i++)
            rc.setSingleNotifications (this, user.msg [i]);
    }
}

AndroidManifest包括:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<receiver android:name=".MyReceiver">
            <intent-filter>
                <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
                <action android:name="android.media.action.DISPLAY_NOTIFICATION" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

        <receiver
            android:name=".RestartReceiver"
            android:enabled="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <service android:name="myPackageName.RestartService"
            android:exported="false"/>



推荐阅读