I am getting a lot of these errors:
android.app.RemoteServiceException:
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1772)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loop (Looper.java:193)
at android.app.ActivityThread.main (ActivityThread.java:6758)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:912)
They only seem to happen on Android 8.1, 9, 10 and 11. There's not much else that I can see, it seems to happen on some devices. I've searched everywhere for an answer but nobody seems to know what is causing it exactly. I think it might be something related to the notification channel but maybe not. I tried startForeground() in both onCreate() and onStartCommand() and it doesn't make any difference. I am getting these errors for 5 years in my app and I simply cannot reproduce it on my end. This is my service code:
public static boolean service = false;
public static Context appContext;
public static Handler handler;
public static String notificationText;
#Override
public void onCreate() {
service = true;
appContext = getApplicationContext();
handler = new Handler();
setNotification();
if (notification != null) {
startForeground(1, notification);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public static void setNotification() {
try {
Intent intent = new Intent(appContext, MainActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pIntent = PendingIntent.getActivity(appContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent intentStop = new Intent(appContext, broadcastReceiver.class);
PendingIntent pIntentStop = PendingIntent.getBroadcast(appContext, 0, intentStop, PendingIntent.FLAG_UPDATE_CURRENT);
notification = new NotificationCompat.Builder(appContext, "X")
.setContentTitle("App Title")
.setContentText(notificationText)
.setSmallIcon(R.drawable.ic_notification)
.setAutoCancel(false)
.setOngoing(true)
.setContentIntent(pIntent)
.addAction(0, "Stop", pIntentStop)
.build();
notification.defaults = 0;
NotificationManager notificationManager = (NotificationManager) appContext.getSystemService(NOTIFICATION_SERVICE);
if (notificationManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel("X", "App Title", NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.enableVibration(true);
notificationChannel.setVibrationPattern(new long[]{0});
notificationChannel.setSound(null, null);
notificationManager.createNotificationChannel(notificationChannel);
}
notificationManager.notify(1, notification);
}
} catch (Exception e) {
showToast(appContext, e.getMessage());
}
}
public static class broadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.stopService(new Intent(context, MainService.class));
}
}
Does anyone have any clue on what is going on? Thanks!
Related
I have implemented android notifications in android studio. I was creating notification for a media player. following is the function for showing notifications
public void showNotification(int playPauseBtn)
{
Intent intent = new Intent(this, PlayerActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
Intent prevIntent = new Intent(this, NotificationReceiver.class).setAction(ACTION_PREVIOUS);
PendingIntent prevPending = PendingIntent.getBroadcast(this, 0, prevIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent pauseIntent = new Intent(this, NotificationReceiver.class).setAction(ACTION_PLAY);
PendingIntent pausePending = PendingIntent.getBroadcast(this, 0, pauseIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent nextIntent = new Intent(this, NotificationReceiver.class).setAction(ACTION_NEXT);
PendingIntent nextPending = PendingIntent.getBroadcast(this, 0, nextIntent, PendingIntent.FLAG_UPDATE_CURRENT);
byte[] picture = null;
try
{
picture = getAlbumArt(listSongs.get(position).getPath());
} catch (Exception ignored)
{
}
Bitmap thumb;
if (picture != null)
{
thumb = BitmapFactory.decodeByteArray(picture, 0, picture.length);
} else
{
thumb = BitmapFactory.decodeResource(getResources(), R.drawable.icon_music);
}
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID_1).setSmallIcon(playPauseBtn)
.setLargeIcon(thumb)
.setContentTitle(listSongs.get(position).getTitle())
.setContentText(listSongs.get(position).getArtist())
.addAction(R.drawable.ic_baseline_skip_previous_24, "Previous", prevPending)
.addAction(R.drawable.ic_baseline_skip_next_24, "Next", nextPending)
.addAction(playPauseBtn, "pause", pausePending)
.setStyle(new androidx.media.app.NotificationCompat.MediaStyle().setMediaSession(mediaSessionCompat.getSessionToken()))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setOnlyAlertOnce(true)
.setContentIntent(contentIntent)
.build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
Toast.makeText(PlayerActivity.this, "Nitification created", Toast.LENGTH_SHORT).show();
}
In the function parameter (playPauseBtn) I am sending the play icon or the pause icon depending upon weather the song is playing or is paused.
Function call is made like following:
showNotification(R.drawable.ic_baseline_pause_24);
OR
showNotification(R.drawable.ic_baseline_play_arrow_24);
But when ever I call this function the notification doesn't show up. I am also using the notification channel but still it is not working. I have also tried to debug the code but the code runs fine, still the notification doesn't show up. please advise
try this.
put this code in your Activity/fragment;
public void getNotification(){
int notifId =new Random().nextInt(500); //get random id
NotificationManager notificationManager;
Notification notification;
notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channelID = "1";
channelName = "news";
channelDesc = "news description";
NotificationChannel notificationChannel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH);
notificationChannel.setDescription(channelDesc);
notificationChannel.enableLights(true);
notificationChannel.setSound(null, null);
notificationChannel.setLightColor(Color.GREEN);
notificationManager.createNotificationChannel(notificationChannel);
}
RingtoneManager.getRingtone(mContext,
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)).play();
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, channelID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("title Of MUSIC")
.setContentText("Content")
.setVibrate(new long[]{100, 500, 500, 500, 500})
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_launcher))
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
Intent actionReadMessage = new Intent(mContext, NotifAction.class);
actionReadMessage.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
actionReadMessage.setAction("Play");
actionReadMessage.putExtra("NotifId",notifId);
PendingIntent playPendingIntent = PendingIntent.getBroadcast(mContext, notifId, actionReadMessage,PendingIntent.FLAG_CANCEL_CURRENT);
Intent mainAction = new Intent(mContext, NotifAction.class);
mainAction.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
mainAction.setAction("Pause");
mainAction.putExtra("NotifId",notifId);
PendingIntent PausePendingIntent = PendingIntent.getBroadcast(mContext, notifId, mainAction,PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentIntent(PausePendingIntent);
builder.addAction(R.mipmap.ic_launcher, "Play", playPendingIntent);
builder.addAction(R.mipmap.ic_launcher, "Pause", PausePendingIntent);
notification = builder.build();
notificationManager.notify(notifId, notification);
}
and create class NotifAction.class for handle all action:
public class NotifAction extends BroadcastReceiver {
private static final String TAG = "maybe";
private MediaPlayer mp;
#Override
public void onReceive(final Context context, Intent intent) {
String action = intent.getAction();
Bundle extra = intent.getExtras();
if (extra != null) {
int notifId = extra.getInt("NotifId");
if (action.equals("Play")) {
mp = MediaPlayer.create(context, R.raw.music);
handleMusicState(mp);
} else if (action.equals("Pause")) {
handleMusicState(mp);
setMessageRead(notifId, context);
} else {
Toast.makeText(context, "extra action !", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(context, "Empty extra !", Toast.LENGTH_SHORT).show();
}
}
private void setMessageRead(int id, Context context) {
// other method
clearNotification(id, context);
}
private void clearNotification(int id, Context context) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
}
private void handleMusicState(MediaPlayer mediaPlayer) {
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
else mediaPlayer.start();
}
}
define this receiver to manifest:
note:in tag
<receiver android:name=".NotifAction">
<intent-filter>
<action android:name="Play" />
<action android:name="Pause" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
FIX
Donot use .setMediaSession(mediaSessionCompat.getSessionToken()) in .setStyle() in the code given in the question
simply just use
.setStyle(new androidx.media.app.NotificationCompat.MediaStyle())
How to show Foreground Service activity by clicking Notification? When I use my code, it starts new activity, but I need the activity, where service is working. Here is my code (Android Oreo):
public class APSService : Service
{
public static bool isRunning = false;
public override void OnCreate()
{
base.OnCreate();
}
public override void OnDestroy()
{
isRunning = false;
base.OnDestroy();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
isRunning = true;
byte[] input = intent.GetByteArrayExtra("inputExtra");
Intent notificationIntent = new Intent(this, Java.Lang.Class.FromType((typeof(MainActivity))));
PendingIntent pendingIntent = PendingIntent.GetActivity(this,
0, notificationIntent, 0);
var builder = new NotificationCompat.Builder(this, MainActivity.CHANNEL_ID)
.SetContentTitle("APS Service")
.SetSmallIcon(Resource.Drawable.notifypump)
.SetContentText("Start program...")
.SetContentIntent(pendingIntent);
Notification notification = builder.Build();
StartForeground(1, notification);
//do heavy work on background thread
return StartCommandResult.NotSticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
}
And in MainActivity in OnCreate:
protected override void OnCreate(Bundle savedInstanceState)
{
if (!APSService.isRunning)
{
createNotificationChannel();
startService();
}
else
{
NotificationChannel serviceChannel = new NotificationChannel
(
CHANNEL_ID,
"APS service Channel",
NotificationImportance.Default
);
notificationManager = (NotificationManager)GetSystemService(Java.Lang.Class.FromType((typeof(NotificationManager))));
notificationManager.CreateNotificationChannel(serviceChannel);
UpdateNotification("Loading...");
APSService.isRunning = true;
}
}
I hope you would help for solving this problem. Thanks a lot.
I write a demo about it, here is a GIF.
You can achieve the festure like following code.
[Service]
class MyForegroundService : Service
{
public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
CreateNotificationChannel();
string messageBody = "service starting";
// / Create an Intent for the activity you want to start
Intent resultIntent = new Intent(this,typeof(Activity1));
// Create the TaskStackBuilder and add the intent, which inflates the back stack
TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);
stackBuilder.AddNextIntentWithParentStack(resultIntent);
// Get the PendingIntent containing the entire back stack
PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(0, PendingIntentFlags.UpdateCurrent);
var notification = new Notification.Builder(this, "10111")
.SetContentIntent(resultPendingIntent)
.SetContentTitle("Foreground")
.SetContentText(messageBody)
.SetSmallIcon(Resource.Drawable.main)
.SetOngoing(true)
.Build();
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
//do you work
return StartCommandResult.Sticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}
var channelName = Resources.GetString(Resource.String.channel_name);
var channelDescription = GetString(Resource.String.channel_description);
var channel = new NotificationChannel("10111", channelName, NotificationImportance.Default)
{
Description = channelDescription
};
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
}
Here is my demo.
https://github.com/851265601/ForegroundServiceDemo
It's not clear to me what Activity you want to open
How to show Foreground Service activity
A Foreground service runs independently from your app
You are launching the MainActivity here:
Intent notificationIntent = new Intent(this,Java.Lang.Class.FromType((typeof(MainActivity))));
can you clarify what do want to do here?
ps: I know it's not an answer, can't comment yet
I am running a foreground service via broadcast receiver on boot completed.
It starts the services as desired and take only a a fraction of the device memory use and when I launch the app it increased the device memory usage as it should but when I close the app it still takes too much of memory even though the app has been closed and only the foreground service is running. What I want is really that it should use the same amount of memory after app has been closed as of it was using before the app was opened.
So, I did some digging through Android Profiler and what I found is that when foreground service starts after the boot it only opens Application.class, BroadcastReceiver.class, Service.class and few other background classes. And as I open the app it opens all the above classes and other activities . But when I close the app it still uses the device memory for graphic supports. I don't know how to stop that memory usage after the app has been closed.
Here are some screenshots of my Android Profiler
Before Launching the App through Foreground Notification Memory used 65MB
remember the foreground notification was started from the broadcast receiver after boot complete.
After Launching the app from Notifications Memory used 146 MB
While surfing through activities Memory used 165 MB
After app has been closed Memory used 140 MB
Now I want to know how to achieve the task of using the previous amount of memory use that was 65MB?
Here are my BroadcastReceiver and Service.class code.
Broadcast Receiver
public class BootCompletedIntentListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())){
Intent serviceIntent = new Intent(context,ClipMonitorService.class);
ContextCompat.startForegroundService(context,serviceIntent);
}
}
}
Service
public class ClipMonitorService extends Service {
private static final String TAG = "ClipboardManager";
private ExecutorService mThreadPool = Executors.newSingleThreadExecutor();
private ClipboardManager mClipboardManager;
private PrefManager prefManager;
#Override
public void onCreate() {
super.onCreate();
prefManager = new PrefManager(this);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mClipboardManager != null) {
mClipboardManager.removePrimaryClipChangedListener(
mOnPrimaryClipChangedListener);
}
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Intent settingIntent = new Intent(this, SettingActivity.class);
PendingIntent pendingSettIntent = PendingIntent.getActivity(this, 0, settingIntent, 0);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);
remoteViews.setOnClickPendingIntent(R.id.btn_action, pendingSettIntent);
remoteViews.setTextViewText(R.id.notif_subtitle, "1 Clips copied Today");
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContent(remoteViews)
.setVisibility(Notification.VISIBILITY_SECRET)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setContentIntent(pendingIntent)
.setColor(getResources().getColor(R.color.colorPrimary))
.setShowWhen(false)
.build();
startForeground(1, notification);
mClipboardManager =
(ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
mClipboardManager.addPrimaryClipChangedListener(
mOnPrimaryClipChangedListener);
return START_STICKY;
}
private ClipboardManager.OnPrimaryClipChangedListener mOnPrimaryClipChangedListener =
new ClipboardManager.OnPrimaryClipChangedListener() {
#Override
public void onPrimaryClipChanged() {
Log.d(TAG, "onPrimaryClipChangeds");
try {
String textToPaste = mClipboardManager.getPrimaryClip().getItemAt(0).getText().toString();
if (textToPaste.length() > 200) {
if (prefManager.isClipNotifOns()) {
mThreadPool.execute(new MakeNotifRunnable(
textToPaste));
}
}
} catch (Exception ignored) {
}
}
};
private class MakeNotifRunnable implements Runnable {
private final CharSequence mTextToWrite;
public MakeNotifRunnable(CharSequence text) {
mTextToWrite = text;
}
#Override
public void run() {
Intent notifIntent = new Intent(getApplicationContext(), PostNewsActivity.class);
notifIntent.putExtra("post", mTextToWrite);
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
int notificationId = 2;
String channelId = "channel1";
String channelName = "Clipboard Monitor Notification";
int importance = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
importance = NotificationManager.IMPORTANCE_DEFAULT;
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel mChannel = new NotificationChannel(
channelId, channelName, importance);
notificationManager.createNotificationChannel(mChannel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(), channelId)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle("Verify copied content")
.setContentText(mTextToWrite)
.setAutoCancel(true)
.setOnlyAlertOnce(true);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext());
stackBuilder.addNextIntent(notifIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
notificationManager.notify(notificationId, mBuilder.build());
}
}
}
Help me to reduce memory usage
I'll be thankful for your answer.
P.S: As I am new to android development I may have uploaded too much information with jargons .Pardon me for that.
Basically, I am trying to build an alarm app which has some buttons with some predefined Date and Time. I have tried using AlarmManager and broadcast receiver in the first place but didn't work. So, I used foreground service with alarmManager but still, the alarm doesn't fire when the app is destroyed. I am a newbie. I tried searching the internet but I had no luck. Hope there is a lot of people here to help me out. Thanks in Advance.
Here I am just trying to set only one alarm for testing. Otherwise, I am using a variable as request code for multiple alarms.
AndroidManifest.xml
<receiver android:name=".AlarmReceiver" />
<activity
android:name=".Activity.PlayerDetailsActivity"
android:theme="#style/AppTheme.NoActionBar"></activity>
<activity android:name=".Activity.FixtureActivity" />
<service android:name=".MyService"/>
MyService.java
public class MyService extends Service {
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Started", Toast.LENGTH_SHORT).show();
Log.e("service","service");
long longExtra = intent.getLongExtra(Constants.ALARM_TIME, 0000);
//Testing Area Start
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(longExtra);
int mMin = calendar.get(Calendar.MINUTE);
int mMonth = calendar.get(Calendar.MONTH);
int mDay = calendar.get(Calendar.DAY_OF_MONTH);
int mHour = calendar.get(Calendar.HOUR_OF_DAY);
Log.e("hour min month day"," "+mHour + " : "+mMin+" month : "+mMonth+" "+" Date : "+mDay+" ");
String currentDateTime=getDeviceDateTime();
Log.e("CurrentdateTime",""+currentDateTime);
Log.e("longExtra",""+longExtra);
//Testing Area End
String CHANNEL_ID = "my_channel_01";
NotificationChannel channel = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channel = new NotificationChannel(CHANNEL_ID,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("dfdf")
.setSmallIcon(R.drawable.ic_notifications_black_24dp)
.setContentText("dfdfd").build();
startForeground(3, notification);
}
/*Intent alertIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Log.d("I",""+longExtra);
alarmManager.set(AlarmManager.RTC_WAKEUP, 6000000, PendingIntent.getBroadcast(getApplicationContext(), 0, alertIntent,
PendingIntent.FLAG_ONE_SHOT));*/
AlarmManager manager= (AlarmManager)getSystemService(ALARM_SERVICE);
Intent myIntent;
myIntent = new Intent(getApplicationContext(),AlarmReceiver.class);
myIntent.putExtra("check",true);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,myIntent,0);
Long finalTime =longExtra-System.currentTimeMillis();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
manager.setExact(AlarmManager.RTC_WAKEUP,longExtra,pendingIntent);
}
else
manager.set(AlarmManager.RTC_WAKEUP,longExtra,pendingIntent);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Alarmreceiver.java
public class AlarmReceiver extends BroadcastReceiver
{
public static final String CHANNEL_ID = "47";
#Override
public void onReceive(Context context, Intent intent)
{
intent = new Intent(context, SplashActivity.class);
intent.putExtra("not",true);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationCompat = new NotificationCompat.Builder(context,CHANNEL_ID);
notificationCompat.setSmallIcon(R.drawable.ic_notifications_black_24dp);
notificationCompat.setContentTitle("My Noticiation");
notificationCompat.setContentText(getPreferences(context).getDateTime());
notificationCompat.setContentIntent(pendingIntent);
notificationCompat.setSound(alarmSound);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel name", importance);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
Notification notification = notificationCompat.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(100,notification);
Toast.makeText(context, "Alarm Working", Toast.LENGTH_SHORT).show();
}
}
you have to start your service so then it can set alarm and fire reciever
start it like this from your activity class
Intent intent=new Intent(this,MyService.class);
startService(intent);
Consider using JobScheduler as a persistence mechanism. It is wakeful and handles the wake locks for you. Only downside it's for Android SDK >= 21 (Lollipop).
There's also a new friend in town that does the backward compatibility for you: WorkManager and will work with all version of Android, even below Lollipop.
Intent myIntent;
myIntent = new Intent(this, AlarmReceiver.class);
myIntent.putExtra("check",true);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);
=============================
Would you change your above code like this ?
Intent myIntent;
myIntent = new Intent(this , MyService.class);
myIntent.setAction("REQUEST_FROM_ALARM_MANAGER");
PendingIntent pendingIntent = PendingIntent.getForegroundService(this,0,myIntent,0);
====================================================
And Service class
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mContext = this;
Log.e(TAG, "onStartCommand " + intent);
if(intent == null) {
return START_NOT_STICKY;
}
if("REQUEST_FROM_ALARM_MANAGER".equals(intent.getAction())){
// show Notification here for your foreground service
}
return START_NOT_STICKY;
}
You have to start a service that survive to your app, you can see here how to do it
I need to show the user a notification at the same time every day (based on a user selecting the time it is shown). With API 25 and earlier I can use AlarmManager without a problem. However with API 26 (Oreo) it will crash my app if the app is in the background for more than a few minutes. Nothing I've done seems to prevent AlarmManager crashing after about a minute of the app being in the background.
Based on what I have seen online the only solution is to use a JobScheduler, but there doesn't seem to be anyway to have a JobScheduler start at a certain time and then recur every day. (I can have it run at a certain time by calling setOverrideDeadline or I can make it recurring by calling setPeriodic, but calling both throws and exception.)
This is my code for the JobScheduler (I have it set to recur every 15 seconds for testing, but I also want to be able to start it at a certain time):
private void setReminders(){
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_BOOT_COMPLETED) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.RECEIVE_BOOT_COMPLETED }, 613);
return;
}
SharedPreferences sharedPreferences = this.getSharedPreferences(getString(R.string.shared_pref_file_name), ContextWrapper.MODE_PRIVATE);
boolean showReminder = sharedPreferences.getBoolean(getString(R.string.shared_pref_reminder_active_key), false);
int hour = sharedPreferences.getInt(getString(R.string.shared_pref_reminder_hour_key), 21);
int minute = sharedPreferences.getInt(getString(R.string.shared_pref_reminder_minute_key), 0);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
long startUpTime = Calendar.getInstance().getTimeInMillis() + 10000; //calendar.getTimeInMillis() + 10000;
JobInfo.Builder builder = new JobInfo.Builder( 613, new ComponentName(getPackageName(), SefiraReminderJobService.class.getName()));
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
.setOverrideDeadline(15000)
.setRequiresDeviceIdle(false)
.setRequiresCharging(false)
.setPersisted(true);
builder.setPeriodic(Math.max(15000, JobInfo.getMinPeriodMillis()));
JobScheduler jobScheduler = (JobScheduler) getSystemService( Context.JOB_SCHEDULER_SERVICE );
if(jobScheduler.schedule(builder.build()) == JobScheduler.RESULT_FAILURE ) {
Log.w("MainActivity.setReminders", "Something went wrong when scheduling the reminders" );
}
}
This is my JobIntentService class:
public final class ReminderJobService extends JobIntentService {
private NotificationManager notificationManager;
private PendingIntent pendingIntent;
private static int NOTIFICATION_ID = 1234;
private static String NOTIFICATION_CHANNEL_ID = "my-reminder-channel";
private Notification notification;
#Override
protected void onHandleWork(#NonNull Intent intent) {
Context context = this.getApplicationContext();
notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this, MainActivity.class);
pendingIntent = PendingIntent.getActivity(context, 0, mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Reminders", NotificationManager.IMPORTANCE_DEFAULT);
// Configure the notification channel.
notificationChannel.setDescription("My Reminders");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_launcher_foreground)
//.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_launcher))
//.setTicker("ticker value")
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
.setContentTitle("Reminder")
.setContentText("Reminder Message").build();
notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
notification.ledARGB = 0xFFFFA500;
notification.ledOnMS = 800;
notification.ledOffMS = 1000;
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
notificationManager.notify(NOTIFICATION_ID, notification);
} catch (Exception ex){
ex.printStackTrace();
}
}
}
My AndroidManifest contains the following:
<service android:name="ReminderJobService"
android:permission="android.permission.BIND_JOB_SERVICE"></service>
As well as:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
How can I send a recurring notification each day at a specific time on Android 26/8.0/Oreo even when the app is in the background?
This workable decision but with deprecated logic:
public scheduleEvent(int id, long scheduleTime) {
final PendingIntent pendingIntent = pendingIntent(id);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduleTime, pendingIntent);
}
private PendingIntent pendingIntent(int id) {
final Intent intent = new Intent(app, EventReceiver.class);
intent.setAction("some event " + id);
return PendingIntent.getBroadcast(context, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Create EventReceiver don't forget add it in AndroidManifest
public class EventReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final ComponentName comp = new ComponentName(context.getPackageName(), EventService.class.getName());
startWakefulService(context, intent.setComponent(comp));
}
}
Create EventService, also add it to the AndroidManifest
public class EventService extends IntentService {
#Override
protected void onHandleIntent(final Intent intent) {
//Your logic here
}
}