Destroy foreground notification when the service get killed - java

I have a foreground service to download some contents form the web.
Unfortunately, due to bug which reported here my service being killed when a receiver received a broadcast within my service but it's notification won't be killed and I saw the following log in my logcat:
I/ActivityManager(449): Killing 11073:my-package-name/u0a102 (adj 0): remove task
Is there anyway to to destroy foreground notification when it's parent service get killed by OS?

Service ending remove the foreground notification.
#Override
public void onDestroy() {
// mycleanup first
stopForeground(true);
super.onDestroy();
}

Use stopForeground:
#Override
public void onDestroy() {
// as the bug seems to exists for android 4.4
if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.KITKAT)
{
stopForeground(true);
}
super.onDestroy();
}
or
public void onTaskRemoved (Intent rootIntent)
{
// as the bug seems to exists for android 4.4
if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.KITKAT)
{
stopForeground(true);
}
}

Inside the notification check periodically (e.g. Handler) if service is still running using code below:
public static boolean isMyServiceRunning(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MyService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
And if not just shut down notification.
private static final int DEALY = 10000;
private Handler handler = new Handler();
...
handler.postDelayed(ensureSericeIsRunning, DELAY);
...
private Runnable ensureSericeIsRunning = new Runnable() {
#Override
public void run() {
if (!isMyServiceRunning(getActivity())){
//shut down notification
} else {
handler.postDelayed(ensureSericeIsRunning, DELAY);
}
}
};

use onDestroy(). Even tho the documentation says it is not guaranteed to be called, I have tested multiple times and the only cases it doesn't get called is when the system kills the process, but to that point your notification will be killed to, so it's ok.

You could remove the notification from onStop or onDestroy inside of your service class.
P.S there no guarantee this would work, in api 14 and above the service can still be running even without foreground notification, you could return START_STICKY that will bring back your service even if the system destroyed it, system will restart it.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}

use the service onTaskRemoved() method.

Related

Service get stopped on app closing

I am working on a wallpaper application in which i am setting a gallery of images on wallpaper with shuffle effect for 5 min, 10 min etc. I am using service for this task. My service works well when app remains in background, but service get stopped when app get stopped.This is my code for service class:
public class WallpaperService extends Service {
ArrayList<String> arrayList;int counter = 0;
boolean serviceStopped;
private IBinder binder = new WallpaperServiceBinder();
public WallpaperService() {
}
private Handler mHandler;
private Runnable updateRunnable = new Runnable() {
#Override
public void run() {
if (serviceStopped == false)
{
createNotificationIcon();
}
queueRunnable();
}
};
public class WallpaperServiceBinder extends Binder {
public WallpaperService getService() {
return WallpaperService.this;
}
}
private void queueRunnable() {
// 600000 : cada 10 minutos, comprueba si hay nuevas notificaciones y actualiza la
// notification BAR
mHandler.postDelayed(updateRunnable, 5000);
}
#Override
public int onStartCommand(Intent intent,int flag, int start_id){
super.onStartCommand(intent,flag,start_id);
arrayList = intent.getStringArrayListExtra("image_url");
return START_STICKY;
}
#Override
public void onRebind(Intent intent) {
Log.v("Service","in onRebind");
super.onRebind(intent);
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public void onCreate() {
serviceStopped = false;
mHandler = new Handler();
queueRunnable();
}
#Override
public void onStart(Intent intent, int startid) {
}
public void createNotificationIcon()
{
counter += 1;
Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show();
Picasso.with(getApplicationContext()).load(arrayList.get(counter)).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
try {
final WallpaperManager wallpaperManager =
WallpaperManager.getInstance(getApplicationContext());
wallpaperManager.setBitmap(bitmap);
wallpaperManager.suggestDesiredDimensions(1080, 1920);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
//Here you should place a loading gif in the ImageView to
//while image is being obtained.
}
});
}}
This is the code i am using to start service:
Intent intent = new Intent(CategoryActivity.this,WallpaperService.class);
intent.putExtra("image_url",img_urls);
intent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startService(intent);
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
Have you added these lines in manifest file
<application> <service android:name=".ExampleService" /></application>
 
Important Fact about the bindService
If a component calls bindService() to create the service and onStartCommand() is not called, the service runs only as long as the component is bound to it. After the service is unbound from all of its clients, the system destroys it.
Try using Started Service
A started service is one that another component starts by calling
startService(), which results in a call to the service's
onStartCommand() method.
When a service is started, it has a lifecycle that's independent of
the component that started it. The service can run in the background
indefinitely, even if the component that started it is destroyed. As
such, the service should stop itself when its job is complete by
calling stopSelf(), or another component can stop it by calling
stopService().
An application component such as an activity can start the service by
calling startService() and passing an Intent that specifies the
service and includes any data for the service to use. The service
receives this Intent in the onStartCommand() method.
Handling onStartCommand
Notice that the onStartCommand() method must return an integer. The
integer is a value that describes how the system should continue the
service in the event that the system kills it. The default
implementation for IntentService handles this for you, but you are
able to modify it. The return value from onStartCommand() must be one
of the following constants:
START_NOT_STICKY If the system kills the service after onStartCommand() returns, do not recreate the service unless there are
pending intents to deliver. This is the safest option to avoid running
your service when not necessary and when your application can simply
restart any unfinished jobs.
START_STICKY If the system kills the service after onStartCommand() returns, recreate the service and call
onStartCommand(), but do not redeliver the last intent. Instead, the
system calls onStartCommand() with a null intent unless there are
pending intents to start the service. In that case, those intents are
delivered. This is suitable for media players (or similar services)
that are not executing commands but are running indefinitely and
waiting for a job.
START_REDELIVER_INTENT If the system kills the service after onStartCommand() returns, recreate the service and call
onStartCommand() with the last intent that was delivered to the
service. Any pending intents are delivered in turn. This is suitable
for services that are actively performing a job that should be
immediately resumed, such as downloading a file.
Note: In your case you should use Started Service and return START_STICKY or START_REDELIVER_INTENT (based on your requirement) in onStartCommand()
Check Official Documentation for detailed description of the Services.

Android service in own thread is killed together with app process

I have a service declared in manifest like
<service android:name=".services.ScreenOnService" android:process="#string/screenProcess"/>
all the service does is registering for Screen_on broadcast (As i always need the information that the Screen was turned on and not only if my app is running)
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
//All this service has to do is register for the screen on broadcast
//as this one can't be registere in manifest and the ACTION_USER_PRESENT is
//not guaranteed to be fired. (E.g. if no lock screen is used)
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
registerReceiver(screenEventReceiver,filter);
return START_STICKY;
}
#Override
public void onDestroy()
{
unregisterReceiver(screenEventReceiver);
super.onDestroy();
}
I start the service from my Application onCreate
#Override
public void onCreate() {
super.onCreate();
if(!isScreenOnServiceAlreadyRunning())
{
//Start the screen on service
Intent screenOnService = new Intent(this, ScreenOnService.class);
startService(screenOnService);
}
}
Everything is fine as long as the app is running. If I kill the app, the service in it's own process is also killed and I don't get why.
I found a promising article here http://fabcirablog.weebly.com/blog/creating-a-never-ending-background-service-in-android and hoped the best but even if I do this and send a broadcast, it will not work.
Why does the service stop working if the app is killed? I assumed it will keep running, as it's in it's own process. If what I want is not realisable with my approach, what's the best way to do so?
Thanks already.
#Hardcore_Graverobber I think you should start the service as a separate process,
please refer this tutorial
http://www.vogella.com/tutorials/AndroidServices/article.html

Not able to stop Service when Broadcast Receiver is registered in Service

I am having a BroadcastReceiver in a Service.
I am registering receiver in service's oncreate() method like,
final MyReceiver myReceiver = new MyReceiver();
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter(SOME_FILTER);
registerReceiver(myReceiver, filter);
}
Then I have created a method to unregister receiver and stop service like,
public void stopService(){
if(myReceiver != null){
try{
unregisterReceiver(myReceiver);
}catch(Exception e){
e.printStackTrace();
}
}
stopSelf();
}
But it does not stop the service. There is no exception, no error. Simply the service doesn't stop.
I have also tried it following way,
public void stopService(){
if(myReceiver != null){
try{
unregisterReceiver(myReceiver);
}catch(Exception e){
e.printStackTrace();
}
}
stopForeground(true);
stopSelf();
}
By doing this the Notification of Service being run in foreground hides but service's onDestroy() is not being called.
I also tried to put the code to unregister receiver in onDestroy() but after calling stopSelf() method onDestroy() is never called.
If I don't register the BroadcastReceiver in the service, everything works perfectly fine, service stops and onDestroy() gets called but when I register receiver then it doesn't stop.
Any ideas what's going on here?
Edit
This is how I am binding and starting the service
Intent serviceIntent = new Intent(MainActivity.this, MyService.class);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
startService(serviceIntent);
And this is mConnection
MyService myService;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service){
LocalBinder binder = (LocalBinder) service;
myService = binder.getService();
isBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
Below is how I am unbinding the service and stopping it.
if(isBound){
unbindService(mConnection);
isBound = false;
}
myService.stopService();
myService = null;
While a Service is bound, it will never be destroyed.
http://developer.android.com/reference/android/app/Service.html
A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().
While it is perfectly OK to have a Service that is both, bound and started, it makes for iffy lifecycle management issues (as you've just found out). If possible, you should decide if you need loose or tight coupling of your Service and then use a started or bound Service respectively. This will make your life easier.
Just found a solution of the same by hit and trial method.
I shifted the code to unregister the receiver in onDestroy() method and all worked.
#Override
public void onDestroy() {
super.onDestroy();
if(myReceiver != null){
try{
unregisterReceiver(myReceiver);
}catch(Exception e){
e.printStackTrace();
}
}
}
I think problem was occurring because I was trying to unregister the receiver before stopping the service.

Service code stops when application is stopped

I have an app that gets users messages from database and if there is a new message it pushes a notification i use a service for that.. The service works fine when the app is opened or in the foreground.. But when I close it it doesn't work.. It is not destroyed or stopped it's just doesn't work :S I don't know why.. This is my service code :
public class BGService extends Service {
ArrayList<Message> messages = new ArrayList<Message>();
ArrayList<String> requests = new ArrayList<String>();
Timer timer = new Timer();
Timer timer2 = new Timer();
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onDestroy() {
Log.d("Chat", "BGService Destroyed");
timer.cancel();
timer.purge();
timer2.cancel();
timer2.purge();
}
#SuppressWarnings("unchecked")
#Override
public void onStart(Intent intent, int startId) {
Log.d("Chat", "BGService Started");
messages = (ArrayList<Message>) intent.getExtras().get("messages");
requests = (ArrayList<String>) intent.getExtras().get("requests");
Log.d("Button Clicked", "Messages: " + messages);
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
Log.d("Service", "Running");
}
}, 2000, 2000);
}
}
Your telling the service to stop in your code. Because your using onBind() it appears that your not starting the service and instead binging to it. If you bind to a service the service automatically ends when your activity ends.
If you want to keep your service running.
Start the service to keep service running
Bind to the service to have a service while app is running
Set a notification so the service is in the foreground
Change your manifest so the service runs in a separate process
Start the service so you can return startsticky in the onStartCommand() to tell the os you want this to stick on
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
Start Service. Bind to the service only if you have a connection to communicate with the service back and forth with. This is returned from onBind()
startService(new Intent(context, ServiceLocationRecorder.class));
// bind to the service
if (!mIsBound) {
// Bind to the service
bindService(new Intent(context,
ServiceLocationRecorder.class), mConnection,
Context.BIND_AUTO_CREATE);
mIsBound = true;
}
Binding to the service is used to setup a binder handler that you can communicate to and from the service with. Returning null in onBind() defeats the purpose of the onBind() event so you could skip this code.
/**
* When binding to the service, we return an interface to our messenger for
* sending messages to the service.
*/
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
set the service to the foreground you do this and the os will be less likely to end your service to get memory for another app.
//this is done inside the service
startForeground(R.id.action_record, getMyCustomNotification());
Run the service in its own process then GC will be able to collect your activity and keep the service running.
<service
android:name="com.example.service"
android:process=":myseparateprocess" >s -->
</service>

Sending intents from service to activity only when activity is running

I have a service and application. There is communication between them by sending intents on specific situations. In activity I register and unregister broadcast receiver to collect this intents. Intents from service are sending when particular callback method is executed. Is there a possibility to send this intents only when activity is in the foreground? Because when this is hide there is no need to gather this intents (it helpful only to show some situations in real time)? I figure out that in activity could be static field that indicates about such situation, but I don't know how to get access to activity from service and additionally I found information that this is vary bad design practise.. Thank for any suggestions!
Declare this in your Activity:
public static boolean isRunning;
Then in your onPause to set isRunning = false;
and in onResume set it to isRunning = true;
Then from your Service you can simply call ActivityName.isRunning to know if it is in foreground or not!
you can use a static variable within the activity.
class MyActivity extends Activity {
static boolean active = false;
#Override
public void onStart() {
super.onStart();
active = true;
}
#Override
public void onStop() {
super.onStop();
active = false;
}
}
Add just check in service as
if(MyActivity.active)
{
//send broadcast.
}
OR
go with this to check status of activity is it active or not
public boolean isRunning(Context ctx) {
ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (RunningTaskInfo task : tasks) {
if (ctx.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName()))
return true;
}
return false;
}
I'd have a local boolean variable in service:
protected boolean mIsAppRunning;
Call startService() with true/false extra when app resumes/stops:
#Override
protected void onResume() {
super.onResume();
Intent service = new Intent("my.service.ACTION");
service.putExtra("IS_MY_ACTIVITY_RUNNING", true);
startService(service);
}
#Override
protected void onPause() {
Intent service = new Intent("my.service.ACTION");
service.putExtra("IS_MY_ACTIVITY_RUNNING", false);
startService(service);
}
Check that extra in service's onStartCommand() and assign its value to mIsAppRunning:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
mIsAppRunning = intent.getBooleanExtra("IS_MY_ACTIVITY_RUNNING", false);
}
return START_STICKY;
}
If you design the logic in the service a little carefully, you may even get rid of the local variable, mIsAppRunning, and call the required methods depending on the intent extra value.
Hope this helps.

Categories

Resources