应用被杀死时,AlarmManager在前台服务中不起作用

时间:2018-10-05 20:11:23

标签: java android service broadcastreceiver alarmmanager

我的应用程序应在指定的时间发送通知。  我编写了一个使用AlarmManager的服务,该服务是一个接收器,如果您关闭该应用程序,它将重新启动它。服务重新启动(从日志中可以看到),但是在应用程序关闭时,AlarmManager不起作用(接收者没有收到来自它的意图)。我还尝试在服务代码中注册接收器-仍然无法正常工作( AlarmService-前台服务。 AlarmSetter-设置警报的类。 AlarmReceiver-接收方发送通知(已记录:接收到意图)

清单文件:

    <?xml version="1.0" encoding="utf-8"?>
        <manifest
            xmlns:android="http://schemas.android.com/apk/res/android"
            package="net.ozero.drugsreminder"
            android:installLocation="internalOnly">

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

            <application
                android:name=".App"
                android:allowBackup="true"
                android:icon="@mipmap/ic_launcher"
                android:label="@string/app_name"
                android:roundIcon="@mipmap/ic_launcher_round"
                android:supportsRtl="true"
                android:theme="@style/AppTheme"
                >

                <activity android:name=".activities.MainActivity">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN" />

                        <category android:name="android.intent.category.LAUNCHER" />
                    </intent-filter>
                </activity>
                <activity
                    android:name=".activities.AddPrescActivity"
                    android:label="@string/label_add_presc_activity"
                    android:parentActivityName=".activities.MainActivity"
                    android:theme="@style/ActionBarTheme"
                    android:windowSoftInputMode="stateHidden">
                    <intent-filter>
                        <action android:name="android.intent.action.VIEW" />

                        <category android:name="android.intent.category.DEFAULT" />
                    </intent-filter>
                </activity>
                <activity
                    android:name=".activities.AddDrugActivity"
                    android:label="@string/label_add_drug_activity"
                    android:parentActivityName=".activities.AddPrescActivity"
                    android:theme="@style/ActionBarTheme"
                    android:windowSoftInputMode="stateVisible">
                    <intent-filter>
                        <action android:name="android.intent.action.VIEW" />

                        <category android:name="android.intent.category.DEFAULT" />
                    </intent-filter>
                </activity>
                <activity android:name=".activities.AlarmActivity">
                    <intent-filter>
                        <action android:name="android.intent.action.VIEW" />

                        <category android:name="android.intent.category.DEFAULT" />
                    </intent-filter>
                </activity>

                <service
                    android:name=".services.AlarmService"
                    android:enabled="true"
                    android:exported="true" >
                    <intent-filter>
                        <action android:name="net.ozero.drugsreminder.services.AlarmService.MarkEvent" />
                        <action android:name="net.ozero.drugsreminder.services.AlarmService.SetLater" />
                    </intent-filter>
                </service>
                <receiver
                    android:name=".services.AlarmReceiver"
                    android:enabled="true"
                    android:exported="true">
                    <intent-filter>
                        <action android:name="net.ozero.drugsreminder.services.AlarmReceiver" />
                    </intent-filter>
                </receiver>
                <receiver
                    android:name=".services.RestartAlarmServiceReceiver"
                    android:enabled="true"
                    android:exported="true">
                </receiver>
                <receiver
                    android:name=".services.BootCompleteReceiver"
                    android:enabled="true"
                    android:exported="true">
                    <intent-filter>
                        <action android:name="android.intent.action.BOOT_COMPLETED" />
                        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                        <action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
                    </intent-filter>
                </receiver>
            </application>

        </manifest>

AlarmService:

    package net.ozero.drugsreminder.services;

        import android.app.AlarmManager;
        import android.app.NotificationManager;
        import android.app.Service;
        import android.content.Intent;
        import android.os.IBinder;
        import android.util.Log;

        import net.ozero.drugsreminder.alarm.AlarmSetter;
        import net.ozero.drugsreminder.database.DBHelper;
        import net.ozero.drugsreminder.datastructure.Event;
        import net.ozero.drugsreminder.formatters.AlarmMessageBuilder;

        import java.util.List;

        import static net.ozero.drugsreminder.App.*;
        import static net.ozero.drugsreminder.App.EXTRA_ALARM_ID;

        /**TODO alarm repeating (bug) */
        public class AlarmService extends Service {

            public AlarmService() {
            }

            public DBHelper mDBHelper;
            public AlarmReceiver mAlarmReceiver;
            public AlarmManager mAlarmManager;

            @Override
            public int onStartCommand(Intent intent, int flags, int startId) {

                Log.i("AlarmService:", "on start");

        //        mAlarmReceiver = new AlarmReceiver();

                mDBHelper = new DBHelper(this);

                //set event is done
                if (isMarkAction(intent)) {
                    markEvent(intent);
                }

                //set event to alarm later
                if (isSetLaterAction(intent)) {
                    setEventLater(intent);
                }
                setAlarms();

                return START_STICKY;
            }

            @Override
            public IBinder onBind(Intent intent) {
                throw new UnsupportedOperationException("Not yet implemented");
            }

            @Override
            public void onTaskRemoved(Intent rootIntent) {
                Log.i("AlarmService:", "on removed");
                sendBroadcast(new Intent(this, RestartAlarmServiceReceiver.class));

                Log.i(getClass().getName(), "OnTaskRemoves: broadcast sent");

                super.onTaskRemoved(rootIntent);
            }

            private boolean isMarkAction(Intent intent) {
                return (
                        intent != null
                        && intent.getAction() != null
                        && intent.getAction().equals(ACTION_MARK_EVENT)
                );
            }

            private boolean isSetLaterAction(Intent intent) {
                return (
                        intent != null
                                && intent.getAction() != null
                                && intent.getAction().equals(ACTION_SET_LATER)
                );
            }

            private void setEventLater(Intent intent) {
                int id = intent.getIntExtra(EXTRA_ALARM_ID, 0);
                mDBHelper.setEventLater(id, ALARM_INTERVAL);
                NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                assert notificationManager != null;
                notificationManager.cancel(id);
                Log.i("AlarmService:", "event time set later : " + id);
            }

            private void markEvent(Intent intent) {
                int id = intent.getIntExtra(EXTRA_ALARM_ID, 0);
                mDBHelper.markEvent(id);
                NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                assert notificationManager != null;
                notificationManager.cancel(id);
                Log.i("AlarmService:", "event is marked, id : " + id);
            }

            private void setAlarms() {

                mDBHelper = new DBHelper(this);

                List<Event> events = mDBHelper.getActualEvents();

                Log.i("AlarmService:setAlarms:", "actual (not marked) events size:" + String.valueOf(events.size()));

                AlarmSetter alarmSetter = new AlarmSetter(this);
                AlarmMessageBuilder alarmMessageBuilder = new AlarmMessageBuilder(mDBHelper);

                for (Event event : events) {

                    long timeMillis = event.getReceptionDateTime().getTime();
                    String message = alarmMessageBuilder.getMessage(event);
                    int id = event.getId();

                    alarmSetter.setAlarm(timeMillis, message, id);
                }
            }

            @Override
            public void onDestroy() {
                super.onDestroy();

                Log.i(getClass().getName(), "onDestroy");
            }
        }

AlarmSetter:

    package net.ozero.drugsreminder.alarm;

        import android.app.AlarmManager;
        import android.app.PendingIntent;
        import android.content.Context;
        import android.content.Intent;
        import android.os.Build;
        import android.util.Log;

        import net.ozero.drugsreminder.services.AlarmReceiver;

        import static net.ozero.drugsreminder.App.EXTRA_ALARM_ID;
        import static net.ozero.drugsreminder.App.EXTRA_ALARM_MESSAGE;

        public class AlarmSetter {

            //one minute timeout
            public static final long DEFAULT_ALARM_TIMEOUT = 60*1000L;

            private Context mContext;
            private AlarmManager mAlarmManager;

            public AlarmSetter(Context applicationContext) {
                mContext = applicationContext;
                mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
                Log.i("AlarmSetter:", "alarm manager:" + mAlarmManager);
            }

            //main method
            public void setAlarm(long timeMillis, String message, int id) {

                //creating intent for alarm message
                Intent intent = new Intent("net.ozero.drugsreminder.services.AlarmReceiver");
                intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
                intent.putExtra(EXTRA_ALARM_MESSAGE, message);
                intent.putExtra(EXTRA_ALARM_ID, id);

                //creating pending intent
                PendingIntent pendingIntent = PendingIntent.getBroadcast(
                        mContext.getApplicationContext(), id, intent, 0);

                //setting alarm
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    mAlarmManager.setExactAndAllowWhileIdle(
                            AlarmManager.RTC_WAKEUP,
                            timeMillis,
                            pendingIntent
                    );
                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    mAlarmManager.setExact(
                            AlarmManager.RTC_WAKEUP,
                            timeMillis,
                            pendingIntent
                    );
                } else {
                    mAlarmManager.set(
                            AlarmManager.RTC_WAKEUP,
                            timeMillis,
                            pendingIntent
                    );
                }

                Log.i("AlarmSetter:" , "alarm set");
            }

        }

AlarmReceiver:

    package net.ozero.drugsreminder.services;

        import android.content.BroadcastReceiver;
        import android.content.Context;
        import android.content.Intent;
        import android.util.Log;

        import net.ozero.drugsreminder.alarm.NotificationSetter;

        import static net.ozero.drugsreminder.App.EXTRA_ALARM_ID;
        import static net.ozero.drugsreminder.App.EXTRA_ALARM_MESSAGE;

        public class AlarmReceiver extends BroadcastReceiver {

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

                Log.i("AlarmReceiver:", "notification received");

                String message = intent.getStringExtra(EXTRA_ALARM_MESSAGE);
                int id = intent.getIntExtra(EXTRA_ALARM_ID, 1);
                NotificationSetter notificationSetter = new NotificationSetter(context);
                notificationSetter.setNotification(message, id);
            }
        }

1 个答案:

答案 0 :(得分:0)

您必须将您的服务作为真正的前台服务来运行,这样即使您的应用已完成,他也将幸免于难。

这是来自http://www.vogella.com/tutorials/AndroidServices/article.html的一个简单示例:

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);