Мое приложение должно отправлять уведомления в указанное время.Я написал сервис, который использует 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);
}
}