I have the following scheme:
Activity A -which can start Activity B.
Activity B has a background Service it uses which is triggered by an Alarm as follows:
alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
serviceSaveSample = new Intent(getApplicationContext(),
SaveSampleService.class);
alarmSaveSample = PendingIntent.getService(getApplicationContext(),
9988766, serviceSaveSample, PendingIntent.FLAG_UPDATE_CURRENT);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (secondsToSample * 1000), secondsToSample * 1000,
alarmSaveSample);
The service implementation:
public class SaveSampleService extends Service { ...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, RunActivity.class), 0);
Notification notif = new NotificationCompat.Builder(
getApplicationContext()).setAutoCancel(true)
.setContentText("message").setSmallIcon(R.drawable.logo)
.setAutoCancel(true)
.setSmallIcon(R.drawable.logo)
.setContentIntent(contentIntent)
.build();
startForeground(startId, notif);
// some work...
return START_STICKY;
}
the problem is that if i move the app to the background when Activity B is at the top of the stack and the service is running, the service restarts itself after i have closed Activity B explicitly.
i have tried any, if not all flags and still this problem persists.
tried setting the launchMode to any of the values and still not working.
any suggestions?
You need to call the cancel method of AlarmManager, and stopService in your activity onStop.
Check the Services life cycle http://developer.android.com/guide/components/services.html#StartingAService
Related
I tried by setting android:isolatedProcess="true" but it's not working
actually I want to show a permanent notification all time
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), resourceIcon/*R.mipmap.ic_launcher*/))
.setSmallIcon(R.drawable.ic_icon_flo_not)
.setContentTitle(title)
.setOngoing(onGoing)
.setAutoCancel(autoCancelable)
.setPriority(priority)
.setContentText(message);
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
if (playSound)
mBuilder.setSound(soundUri);
if (remoteViews == null) {
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, resultClass);
resultIntent.setAction(action);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
} else {
mBuilder.setContent(remoteViews);
}
Override onTaskRemoved() in your service and use alarm manager to start the service again. Below is code .
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.d(TAG, "TASK REMOVED");
PendingIntent service = PendingIntent.getService(
getApplicationContext(),
1001,
new Intent(getApplicationContext(), MyService.class),
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
}
Service.START_STICKY service are those which are restarted if they are terminated due to some reason.You just need to return Service.START_STICKY from onStartCommand
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
You just need to do above, There is no separate thing that you have to do
The service does get re-created, not re-started.
If you override the onCreate and do a Log.d or a Toast, you will see that onCreate gets called after your activity and app is destroyed.
So the trick to keep it running after it is re-created is to do your code on the onCreate method and use the onStartCommand just to return START_STICKY.
Another thing to notice (and since I can't comment, I'd like to add to Abdul Kawee answer with the AlarmManager):
It is SOLVED on api27: all you have to do is move your super.onTaskRemoved(rootIntent) to be the last line of code.
I have found that destructive methods should only call super in the end of the overriden method, otherwise some resources are no longer available in runtime.
I am using cordova to build my android application. Since android kills service, i am binding service with a notification to avoid service kill.
Here is my method how i bind the service with notification
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = this.getApplicationContext();
notifyService();
return START_NOT_STICKY;
}
private void notifyService() {
String package_name = this.getApplication().getPackageName();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
this.getApplication().getResources().getIdentifier("icon", "drawable-hdpi", package_name));
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Smart Home")
.setContentText("Smart Home running in background")
.setSmallIcon(this.getApplication().getResources().getIdentifier("icon", "drawable-hdpi", package_name))
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(notificationId, notification);
}
Here's the output
Notification is generated but notification title is not as i set. Also, when i click this notification, it's moving to app info activity. But i want to move to my main activity.
Does anyone faced this same issue? Or my code need any change for cordova?
when i click this notification, it's moving to app info activity. But i want to move to my main activity to achieve this
change this line
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
to this line
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Hope it helps you
Figured it out after a long try. Problem was with my pending intent activity name. Below code worked for me
String package_name = this.getApplication().getPackageName();
Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(package_name);
I have an Android Service class the code for which is as follows:
public class LoginService extends Service {
BroadcastReceiver wifiStateChangeReciever;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("AndroidLearning", "Service onStartCommand Started.");
return Service.START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
Log.i("AndroidLearning", "Service Started.");
final IntentFilter intentFilter = new IntentFilter();
// intentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
intentFilter.addAction("android.net.wifi.STATE_CHANGE");
wifiStateChangeReciever = new WifiStateChangeReciever();
this.registerReceiver(wifiStateChangeReciever, intentFilter, null, null);
Log.i("AndroidLearning", "Reciever Registered.");
}
#Override
public void onDestroy() {
Log.i("AndroidLearning", "Service Destroyed.");
this.unregisterReceiver(wifiStateChangeReciever);
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.w("AndroidLearning", "On Task Remove: FLAG_STOP_WITH_TASK - "
+ ServiceInfo.FLAG_STOP_WITH_TASK);
this.unregisterReceiver(wifiStateChangeReciever);
Intent restartServiceIntent = new Intent(getApplicationContext(),
this.getClass()); restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(
getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
alarmService.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1000, restartServicePendingIntent);
Log.w("AndroidLearning", "End on task removed");
super.onTaskRemoved(rootIntent);
}
}
It registers a BroadcastReciever. The Activity which starts this service has the following code:
Intent intent = new Intent(this, LoginService.class);
startService(intent);
However whenever the Activity is swiped out from the task list (recent) the service is also stopped. I over rode the onTaskRemoved to remedy it but it still does not seem to work and the AlarmManager never starts the pendingIntent. I have tries using both method: set and setExact for the AlarmManager.
I also tried adding the following options to <service> tags
android:stopWithTask="false"
android:process=":remote"
but to no avail.
What am I doing wrong here? Thanks for the help.
I finally found the answer to my own problem. It seems this was a problem with the particular flavor of android that I was running on my phone (Mi UI). There was a separate setting regarding each application whether it needed to be allowed to be restarted or not.
Unless this setting is configured no amount of changing permissions and setting Alarms helped me.
This is a different approach from you but I recently fixed this by adding a notification when the service was running
private void showNotification(){
NotificationCompat.Builder builer = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.logo)
.setContentTitle("Service active")
.setContentText("Your service keeps running")
.setOngoing(true);
mNotificationManager.notify(NOTIFICATION_ID, builer.build());
}
The notification is shown in onStartCommand and dismissed in the service ondestroy method.
You need to start service in foreground if you don't want android to shut it down.
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);
http://developer.android.com/guide/components/services.html#Foreground
If you try this on some devices, sadly, it won't work.
Some OEMs decided to change the normal behavior of what happens when you remove an app from the recent tasks, so they become semi-disabled:
https://issuetracker.google.com/issues/122098785
https://dontkillmyapp.com/
I am implementing an app kind of an app tracker which requires to run the service all the time in background. So the service is called when application is opened and it stops when stopself() is called. Service also consists of a thread which runs all the time. It used to run perfect. But from last few days it stops after sometime. When coming to my app's ui after some task the service stops!
Can anyone suggest me any solution?
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("SERVICE","started");
if(intent != null && intent.getAction() != null)
{
day=intent.getExtras().getInt("day")+5;
Toast.makeText(this, "day" +day, Toast.LENGTH_LONG).show();
apps=intent.getStringArrayListExtra("apps");
items=apps.size();
timer=intent.getIntegerArrayListExtra("timer");
Run[] a=new Run[items];
t=new Thread[items];
for(int i=0;i<items;i++)
{
int sec=0;
app=apps.get(i).toString();
time=timer.get(i);
a[i]=new Run(app, time,sec);
Log.e("APPTIME",app+ " "+time);
t[i]=new Thread(a[i]);
t[i].start();
}
}
return super.onStartCommand(intent, flags, startId);
}
You should start your service as STICKY_SERVICE
Example for starting as STICKY
Thread for START_STICKY and START_NOT_STICKY
You should consider reading this, if you are working on Android KitKat
Try implementing foreground service. foreground service
Foreground service displays notification and is never stopped until you want.
Implement this code snippet in your service's onCreate
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);
I've got an application that needs to show a notification of certain events in a day, depending on the event.
I know how to do it, if I need a service to stay running in the background, or it will run in the background getting these events on certain days.
private void Notificar(String descricaoEvento){
NotificationManager notifier = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "Novo evento no The Point Club", System.currentTimeMillis());
notification.flags |= Notification.DEFAULT_SOUND;
PendingIntent pIntent = PendingIntent.getActivity(this, 0, null, 0);
notification.setLatestEventInfo(this, "Title", descricaoEvento.toString(), pIntent);
notifier.notify(0x007, notification);
}
using this method to call when the right date!
Thanks for listening, I'll try to explain what I'm doing right: I'm making an application for a club party, and the application will show the next event of the celebrations when I open the application, but what I wish is that a notification is created in android notification bar, on which there is a party, serving as a reminder.
I use this code when I open the activity to list events:
Calendar c = Calendar.getInstance();
c.setTimeInMillis(System.currentTimeMillis());
int anoAtual= c.get(Calendar.YEAR);
long time = c.getTimeInMillis();
Intent it = new Intent("EXECUTAR_ALARME")
p = PendingIntent.getBroadcast(Eventos.this, 0, it, 0);
AlarmManager alarme = (AlarmManager) getSystemService(ALARM_SERVICE);
alarme.set(AlarmManager.RTC_WAKEUP, time, p);
the line
Intent it = new Intent("EXECUTAR_ALARME")
will call the class:
public class Alarm extends BroadcastReceiver{ #Override
public void onReceive(Context contexto, Intent intent) {
NotificationManager notifier =(NotificationManager) contexto.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "New event in Club", System.currentTimeMillis());
notification.flags |= Notification.DEFAULT_SOUND;
//Intent i = new Intent(this, Eventos.class);
PendingIntent pIntent = PendingIntent.getActivity(contexto, 0, null, 0);
notification.setLatestEventInfo(contexto, "Club", "Teste", pIntent);
notifier.notify(0x007, notification);
}
}
Now I want to know two things:
1 - How do I leave it running in the background without being open with the application.
2 This code only creates only an alarm, and I need to create multiple.
Thanks for the help.
Use AlarmManager to run a PendingIntent at your specific time. At that time, the intent that it stored in the PendingIntent should likely be a service if you're planning on creating a Notification to display to the user. If you could form this as a question, I may be able to help more, but it's unclear what you're trying to accomplish, and what you've managed to accomplish.
Additional Details
In your code, it looks like you're scheduling the alarm for right now, instead of at some time in the future. I'd suggest the following to create the alarm:
Calendar c = Calendar.getInstance();
// don't do this:
// c.setTimeInMillis(System.currentTimeMillis()); // This just sets the alarm time to "now"
// set the calendar to 8:00 pm:
c.set(Calendar.HOUR_OF_DAY, 20);
c.set(Calendar.MINUTE, 0);
long alarmTime = c.getTimeInMillis();
Intent it = new Intent(ServiceClass.getClass());
// Even though the docs say that the request code doesn't matter making it unique tells the alarmManager that it's a different PendingIntent
PendingIntent pendingIntent = PendingIntent.getService(this, 0, it, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.set(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent); // set the first alarm for 8:00
c.set(Calendar.MINUTE, 30);
Intent it2 = new Intnt(ServiceClass.getClass());
PendingIntent pi2 = PendingIntent.getService(this, 0, it2, 0);
alarmMgr.set(AlarmManager.RTC_WAKEUP, alarmTime, pi2); // set the second alarm for 8:30
the line
Intent it = new Intent(ServiceClass.getClass());
will start the Class ServiceClass:
class ServiceClass extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO TRAVIS Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) { // onStartCommand is run when the service is started by the AlarmManager
// build and set the notification here
NotificationManager notifMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// build notification
Notification notification = new Notification.Builder(getApplicationContext())
.setContentTitle("New mail from " + sender.toString())
.setContentText(subject)
.setSmallIcon(R.drawable.new_mail)
.setLargeIcon(aBitmap)
.build();
int ID = 0;
notifMgr.notify(ID++, notification); // use a unique id every time if you want multiple notifications (sounds like what you want, but not a best practice)
notification = new Notification.Builder(getApplicationContext())
.setContentTitle("New event from " + sender.toString())
.setContentText(subject)
.setSmallIcon(R.drawable.new_mail)
.setLargeIcon(aBitmap)
.build();
notifMgr.notify(ID++, notification); // add the second notification to the notification bar
return super.onStartCommand(intent, flags, startId);
}
}
Answers to your questions:
1 - By setting the alarm for sometime in the future, you're asking the OS to start your PendingIntent (in your case, send a Broadcast; in my exmaple above, a Service) at the time specified (that's why you need to set the time with the calendar to sometime in the future!)
2 - Creating multiple alarms is a matter of calling the alarm manager with different PendingIntent s scheduled at the appropriate time (for when you want them to fire). The same is true for Notification s, create multiple ones (with unique ids).