Android: Unable to stop foreground service - android

Simply, I want to upload files over the net using a service.
I have created a service with both: binding and startService. I create a foreground service that displays the progress.
The issue is, after the upload is complete, I call stopForeground(true) and then stopSelf but the notification is not removed and (probably) the service is not killed.
Code of the service class:
public class UploaderService extends Service {
// ...
public void finishUpload(File audioFile, File eventsData) {
LogWrapper.d(TAG, "finishUpload");
mUploadHelper.upload(audioFile, eventsData)
// consider this just a callback:
.subscribe(uuid -> {
// Log is printed but service is not stopped
LogWrapper.d(TAG, "finishUpload.subscribe");
stopForeground(true);
stopSelf();
}, LogWrapper::fatalError);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationCompat.Builder builder = NotificationsManager.getDefaultBuilder(this)
.setProgress(0, 0, true)
.setContentText(intent.getStringExtra(EXTRA_TOPIC_NAME))
.setContentTitle("Uploading data to server");
// first creating a notification with uuid,
// after POST /post call, post.uid will be used.
startForeground(DEAFULT_NOTIFICATION_ID, builder.build());
return START_REDELIVER_INTENT;
}
#Override
public IBinder onBind(Intent intent) {
LogWrapper.d(TAG, "onBind " + intent);
return mUploaderBinder;
}
#Override
public boolean onUnbind(Intent intent) {
LogWrapper.d(TAG, "onUnbind " + intent);
intent.putExtra(EXTRA_TOPIC_NAME, mUploadHelper.getTopic().name);
startService(intent);
return false;
}
#Override
public void onCreate() {
super.onCreate();
mUploaderBinder = new UploaderBinder();
}
public class UploaderBinder extends Binder {
public UploaderService getService() {
return UploaderService.this;
}
}
}

Though I could not find it in docs, the startService command should be called from outside the service i.e. from an Activity. I called it from my activity just before binding to it and it worked as expected.
I was probably experiencing an undefined behavior- the service was starting but not stopping. I wish someone could give me a better explanation of why that was happening, and that this indeed is the correct way to do stuff.
Great thanks to #pskink for pointing me in the right direction.

Related

How to run service in background like WhatsApp does for taking backup of the chat without wake up device?

In my application, I need to do some task at midnight of the everyday. I achieved this using AlarmManager and service, but when my task starts it wakeup the device and launches the app. How can I do that like WhatsApp in the background?
service used for it.
You have create another class then, you have extend Service
public class service extends Service {
// declaring object of MediaPlayer
private MediaPlayer player;
public service() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
onTaskRemoved(intent);
Toast.makeText(getApplicationContext(),"This is a Service running in Background",
Toast.LENGTH_SHORT).show();
player = MediaPlayer.create(getApplicationContext(),R.raw.ringtone);
player.start();
startForegroundService(intent);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartServiceIntent = new Intent(getApplicationContext(),this.getClass());
restartServiceIntent.setPackage(getPackageName());
startService(restartServiceIntent);
super.onTaskRemoved(rootIntent);
}
#Override
public ComponentName startForegroundService(final Intent service) {
return startForegroundService(service);
}
}
To run the source code you have write
Intent intent = new Intent(this, service.class);
ContextCompat.startForegroundService(this,intent);
Alternatively, you can use
startService(new Intent(getApplicationContext(),service.class));
Sometimes above source code works in background in API level 22. Sometimes it gives error. Sometimes it doesn't work.
Here's the git repo
You can use WorkManager, that is the best way IMHO.
I use it for background processing and it works like a charm.
https://developer.android.com/topic/libraries/architecture/workmanager

How to update a notification when a service stopped - Android

I have a Service that downloads a database and displays a notification that contains a progress bar indicating download progress. I want to update that notification when the service stops abruptly like when user kills the app, or app gets killed in the background by the OS. The problem is that the service's onDestroy method never called, so I cannot update the notification and remove its progress bar.
I have tried overriding onTaskRemoved method of the Service and added stopWithTask=true in manifest but that didn't helped. I also overrided onDestroy method of the Activity, and put the code that updates the notification, but that also didn't work.
Here's my service:
public class DatabaseDownloadService extends IntentService {
public static final int DOWNLOAD_NOTIFICATION_ID = 1;
private NotificationManagerCompat mNotificationManager;
private NotificationCompat.Builder mNotificationBuilder;
// For updating the UI on download progress.
private ResultReceiver mResultReceiver;
// If the service is stopped before download process is finished,
// updates the notification.
private boolean mCompleted;
public DatabaseDownloadService() {
super("DatabaseDownloadService");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
Log.print(getClass().getName(), "onHandleIntent");
if (intent == null || intent.getAction() == null)
return;
mResultReceiver = intent.getParcelableExtra("receiver");
// Some code that downloads the file...
}
private void shutdown() {
if (!mCompleted) {
mNotificationBuilder.setContentText("Download did not complete.")
.setColor(getResources().getColor(R.color.error_color_red))
.setSmallIcon(R.drawable.ic_stat_pause)
.setOngoing(false)
.setProgress(0, 0, false);
mNotificationManager.notify(DOWNLOAD_NOTIFICATION_ID, mNotificationBuilder.build());
}
}
#Override
public void onCreate() {
Log.print(getClass().getName(), "onCreate");
super.onCreate();
startForeground(DOWNLOAD_NOTIFICATION_ID, mNotificationBuilder.build());
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onDestroy() {
Log.print(getClass().getName(), "onDestroy");
super.onDestroy();
// This is the code that updates the notification but onDestroy never gets called.
shutdown();
}
}
It should update the notification when the app is killed by Android, or the user. But it doesn't.
How can I solve this issue? I have been searching for a solution for days, and didn't find one, so my only hope is StackOverflow.

Service in android 5.0+

I intended to work like this:
user switches on a feature: let say weather.
now weather data will come from server every 6 hours and will be shown to widget(remoteview), Now user switches off the feature. then widget should not show the weather or even refresh the data every 6 hours.
there are also 3-4 more features like that.
Now i had created a service to get all required data and than i have passed them to remoteview. For starting service i had used this in TimeOut Activity:
i = new Intent(TimeOut.this, TimeService.class);
i.setAction("com.example.Weather.Idle");
startService(i);
same for stopping service in switch off code:
stopService(i)
This code was working fine in API <=19. But in Lollipop it crashes at starting or stoping service.
I searched a lot in SO and also tried code for Binding or unbinding service but didn't help any.
Please help me with some code rather than just links...
Thanks in advance :)
Starting a service from any activity class
Intent intent = new Intent(MainActivity.this, BackgroundService.class);
startService(intent);
Here is service class code
public class BackgroundService extends Service{
public static Context appContext = null;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
if (appContext == null) {
appContext = getBaseContext();
}
Toast.makeText(appContext, "Services Started", Toast.LENGTH_SHORT).show();
return START_STICKY;
}
Add your logic here. You can do some work here using a thread. You can stop service whenever you want and i hope you will not find any crash.
I have faced similar issue with Service in 5.0. This is probably not the correct answer, but it works. You could try. I use EventBus to communicate with my services. So when I want to stop the service I'd send,
EventBus.getDefault().post(new ServiceEvent(ServiceEvent.STOP_SERVICE));
In the service,
public void onEvent(ServiceEvent event) {
if (event.getEvent() == ServiceEvent.STOP_SERVICE) {
methodToStopService();
}
}
private void methodToStopService() {
// do some stuff
stopSelf();
}
Make sure you register your service for events.
private void registerEventBus() {
EventBus eventBus = EventBus.getDefault();
if (!eventBus.isRegistered(this)) {
eventBus.register(this);
}
}
ServiceEvent class - It's my own class which I use with EventBus.
public class ServiceEvent {
private int event;
public static final int STOP_SERVICE = -1;
public ServiceEvent(int event) {
this.event = event;
}
public int getEvent() {
return event;
}
}

Android service not working

I'm trying to call a service class to update the value of a variable from my widget but it doesn't ever seem to get to the service class. I've had a look at some examples and I can't figure out what I'm doing wrong, and I don't really know very much about services yet. All help appreciated.
Service class
public class toggleMonitoringService extends Service{
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate()
{
Log.d("Me","creating service");
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int startId, int something) {
// TODO Auto-generated method stub
String toggle = intent.getExtras().getString("Toggle");
Log.d("Me","Toggle : " + toggle);
if (toggle.equals("app1"))
{
UpdateWidgetService.monitorApp1 = !UpdateWidgetService.monitorApp1;
}
else if (toggle.equals("app2"))
{
UpdateWidgetService.monitorApp2 = !UpdateWidgetService.monitorApp2;
}
super.onStartCommand(intent, startId, something);
return 0;
}
}
Where I set up the intent and pending intent to handle the button click from the widget
Intent monitor1toggle = new Intent(this.getApplicationContext(),toggleMonitoringService.class);
monitor1toggle.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
monitor1toggle.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,allWidgetIds);
monitor1toggle.putExtra("Toggle","app1");
PendingIntent monitor1 = PendingIntent.getService(getApplicationContext(), 0 , monitor1toggle,0);
remoteViews.setOnClickPendingIntent(R.id.firstappstatus, monitor1);
Try start service manually, wihtout using PendingIntent.
Better way is not to start service each time you need to do something, but to start it once, bind to it and use common method calls when you need something from the service.
For your example even a simple Thread would be more appropriate.

How can we prevent a Service from being killed by OS?

I am using Service in my application and it needs to run until my application is uninstalled, but the problem is it gets killed by OS.
How can we prevent it from being killed by OS? Or if it gets killed can we restart that service again through programmatically?
You may run the service in the foreground using startForeground().
A foreground service is a service that's considered to be something
the user is actively aware of and thus not a candidate for the system
to kill when low on memory.
But bear in mind that a foreground service must provide a notification for the status bar (read here), and that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Note: This still does not absolutely guarantee that the service won't be killed under extremely low memory conditions. It only makes it less likely to be killed.
I've been puzzled by the same issue to yours recently.but now,I've found a good solution.
First of all,you should know that, even your service was killed by OS, the onCreate method of your service would be invoked by OS in a short while.So you can do someting with the onCreate method like this:
#Override
public void onCreate() {
Log.d(LOGTAG, "NotificationService.onCreate()...");
//start this service from another class
ServiceManager.startService();
}
#Override
public void onStart(Intent intent, int startId) {
Log.d(LOGTAG, "onStart()...");
//some code of your service starting,such as establish a connection,create a TimerTask or something else
}
the content of "ServiceManager.startService()" is:
public static void startService() {
Log.i(LOGTAG, "ServiceManager.startSerivce()...");
Intent intent = new Intent(NotificationService.class.getName());
context.startService(intent);
}
However, this solution is just available for the situation of your service being killed by GC.Sometimes our service might be killed by user with Programme Manager.In this situation,your prosses will be killed,and your service will never been re-instantiated.So your service can not be restarted.
But the good news is,when the PM kill your service,it will call your onDestroy method.So we can do something with that method.
#Override
public void onDestroy() {
Intent in = new Intent();
in.setAction("YouWillNeverKillMe");
sendBroadcast(in);
Log.d(LOGTAG, "onDestroy()...");
}
The string of "YouWillNeverKillMe" is a custom action.
The most important thing of this method is,don't add any code before send the broadcast.As system will not wait for completion of onDestroy(),you must send out the broadcast as soon as posible.
Then regist a receiver in manifast.xml:
<receiver android:name=".app.ServiceDestroyReceiver" >
<intent-filter>
<action android:name="YouWillNeverKillMe" >
</action>
</intent-filter>
</receiver>
Finally,create a BroadcastReceiver,and start your service in the onReceive method:
#Override
public void onReceive(Context context, Intent intent) {
Log.d(LOGTAG, "ServeiceDestroy onReceive...");
Log.d(LOGTAG, "action:" + intent.getAction());
Log.d(LOGTAG, "ServeiceDestroy auto start service...");
ServiceManager.startService();
}
Hope this will be helpful to you,and excuse my poor written english.
Override method onStartCommand() in your service class and simply return START_STICKY (as suggested by "Its not blank"). That's all you need. If the process that runs your service gets killed (by a low memory condition for example), the Android system will restart it automatically (usually with some delay, like 5 seconds).
Don't use onStart() anymore as suggested in another answer, it's deprecated.
use
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//**Your code **
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
ref Documentation lifecycle of Service.
Edit added method.
As far i know, onDestroy() will be called only when the service is explicitly stopped(Force Stop). But this method won't get called in case the service gets killed by OS/swiping the Recent Apps list. In those cases another event handler named onTaskRemoved(Intent) gets called. This is due to a defect in Android 4.3-4.4 as per the link here. Try using the below code:-
public void onTaskRemoved(Intent intent){
super.onTaskRemoved(intent);
Intent intent=new Intent(this,this.getClass());
startService(intent);
}
I found another solution of the problem which gurantees that your service will be always alive. In my case, this scheme resloves also the problem with FileObserver, which stops work after some period of time.
Use an activity (StartServicesActivity) to start the service (FileObserverService) as Foreground service.
Use BroadcastReceiver class (in example CommonReceiver) to restart your service in some special situations and in case it was killed.
I used this code in my app "Email Pictures Automatically"
https://play.google.com/store/apps/details?id=com.alexpap.EmailPicturesFree
Here is CommonReceiver class.
public class CommonReceiver extends BroadcastReceiver {
public void onReceive(Context paramContext, Intent paramIntent)
{
paramContext.startService(new Intent(paramContext, FileObserverService.class));
}
}
Here is its definition in AndroidManifest.xml just before application closing tag.
<receiver android:name="com.alexpap.services.CommonReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
</receiver>
Start service in StartServicesActivity activity.
Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class);
StartServicesActivity.this.startService(iFileObserver);
Here is onStartCommand() method of the service.
public int onStartCommand(Intent intent, int flags, int startId) {
int res = super.onStartCommand(intent, flags, startId);
/*** Put your code here ***/
startServiceForeground(intent, flags, startId);
return Service.START_STICKY;
}
public int startServiceForeground(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, StartServicesActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("File Observer Service")
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(300, notification);
return START_STICKY;
}
I tested this code using Task Killer app, and each time the service was killed, it was restarted again almost immediately (performs onStartCommand()). It is restarted also each time you turn on the phone and after rebooting.
I use this code in my application, which emails every picture you take with your phone to predefinde list of emails. The sending email and list of receiving emails are set in another activity and are stored in Shared Preferences. I took about 100 pictures in several hours and all they were sent properly to receiving emails.
#Override
public void onDestroy() {
super.onDestroy();
startService(new Intent(this, YourService.class));
}
write above code in your service and your service will never stop even user want to destroy it or they want to kill it it will never kill untill your app not get uninstall from your device
You can try to start your service repeatedly, for example every 5 sec.
This way, when your service is running, it will perform onStartCommand() every 5 sec. I tested this scheme and it is very reliable, but unfortunately it increases slightly phone overhead.
Here is the code in your activity where you start the service.
Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class);
PendingIntent pendingIntentFileObserver = PendingIntent.getService(StartServicesActivity.this, 0, iFileObserver, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Date now = new Date();
//start every 5 seconds
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, now.getTime(), 5*1000, pendingIntentFileObserver);
And here is onStartCommand() of the service.
//class variable
public static boolean isStarted = false;
public int onStartCommand(Intent intent, int flags, int startId) {
int res = super.onStartCommand(intent, flags, startId);
//check if your service is already started
if (isStarted){ //yes - do nothing
return Service.START_STICKY;
} else { //no
isStarted = true;
}
/**** the rest of your code ***/
return Service.START_STICKY;
}
First create service in another process, and write broadcaster which runs in recursion in time intervals
protected CountDownTimer rebootService = new CountDownTimer(9000, 9000) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
sendBroadcast(reboot);
this.start();
Log.d(TAG, "rebootService sending PREVENT AUTOREBOT broadcast");
}
};
After that register broadcast receiver in main process also with timer recursion that is launched after first broadcast from service arrived
protected static class ServiceAutoRebooter extends BroadcastReceiver {
private static ServiceAutoRebooter instance = null;
private RebootTimer rebootTimer = null;
private static ServiceAutoRebooter getInstance() {
if (instance == null) {
instance = new ServiceAutoRebooter();
}
return instance;
}
public class RebootTimer extends CountDownTimer {
private Context _context;
private Intent _service;
public RebootTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
_context.startService(_service);
this.cancel();
Log.d(TAG, "Service AutoRebooted");
}
}
#Override
public void onReceive(Context context, Intent intent) {
if (rebootTimer == null) {
Log.d(TAG, "rebootTimer == null");
rebootTimer = new RebootTimer(10000, 10000);
rebootTimer._context = context;
Intent service = new Intent(context, SomeService.class);
rebootTimer._service = service;
rebootTimer.start();
} else {
rebootTimer.cancel();
rebootTimer.start();
Log.d(TAG, "rebootTimer is restarted");
}
}
}
Service will be auto-rebooted if time at RebootTimer (main process) expires, which means that "PREVENT AUTOREBOT" broadcast from service hasn't arrived
i found a solution .... late answer but i wanted to answer...
we can send a broadcast in the ondestroy of the service and create a receiver that receives the broadcast and starts the service again.... when it is destroyed by any reasons...
pls try following:
final Messenger mMessenger = new Messenger(new IncomingHandler());
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
default:
super.handleMessage(msg);
}
}
}
#Override
public void onCreate() {
super.onCreate();
makeServiceForeground();
}
#Override
public IBinder onBind(Intent arg0) {
return mMessenger.getBinder();
}
private void makeServiceForeground() {
IActivityManager am = ActivityManagerNative.getDefault();
try {
am.setProcessForeground(onBind(null), android.os.Process.myPid(), true);
} catch (RemoteException e) {
Log.e("", "cant set to foreground" + e.toString());
}
}
also need add in manifest.xml
<uses-permission android:name="android.permission.SET_PROCESS_LIMIT"/>

Categories

Resources