Android: Stop Foreground Service causing Application crash - android

Prerequisites:
As a part of the requirement for my application, I need to make sure that the application won't be closed (killed) by the Android system while in background. For this purpose I implemented Foreground service, even though I don't do any actual process in background, just maintaining the state of the application. Everything works just fine, except one thing which is not fully clear to me how to fix.
The issue:
Sometimes (only once, for now), I receive this exception:
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground():
This exception is thrown when I'm trying to stop the foreground service while it wasn't actually started.
So, my question is - is there is a way to stop foreground service properly, making sure that it is not running before actually stopping it?
What I found at the moment is that I can have static instance for my service and compare to null before stopping service, or get the list of all services currently running. But all these look like some "hack" workarounds.
Here some code:
MyForegroundService:
public class ForegroundService extends Service {
public static final int NOTIFICATION_ID = 1;
public static final String CHANNEL_ID = "SessionForegroundServiceChannel";
public static final String ACTION_FOREGROUND_START = "ACTION_FOREGROUND_START";
public static final String ACTION_FOREGROUND_STOP = "ACTION_FOREGROUND_STOP";
public static void startForegroundService(Context context) {
Intent intent = new Intent(context, ForegroundService.class);
intent.setAction(ForegroundService.ACTION_FOREGROUND_START);
ContextCompat.startForegroundService(context, intent);
}
public static void stopForegroundService(Context context) {
Intent intent = new Intent(context, ForegroundService.class);
intent.setAction(ForegroundService.ACTION_FOREGROUND_STOP);
ContextCompat.startForegroundService(context, intent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_FOREGROUND_START.equals(intent.getAction())) {
createNotificationChannel();
Intent stopForegroundIntent = new Intent(this, ForegroundServiceBroadcastReceiver.class);
PendingIntent pendingLogoutIntent = PendingIntent.getBroadcast(this,
0, stopForegroundIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
? null
: getString(R.string.app_short_name))
.setContentText(getString(R.string.foreground_description))
.setColor(getResources().getColor(R.color.color))
.setSmallIcon(R.drawable.ic_notification)
.addAction(R.drawable.ic_logout, getString(R.string.logout), pendingLogoutIntent)
.build();
startForeground(NOTIFICATION_ID, notification);
} else if (ACTION_FOREGROUND_STOP.equals(intent.getAction())) {
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
<service
android:name=".ui.ForegroundService"
android:exported="false"
android:stopWithTask="true"/>
I also have BroadcastReceiver and EventBus to listen to some events and stop foreground depending on those events.
Can you please help me, guys?

Let me add more details to what #Pawel commented:
You get this exception if you don't call Service.startForeground within 3 seconds of calling Context.startForegroundService that's all there's to it.
Here is how the complete solution will look like:
When it comes to the case when you need to stop a foreground service you need to do the following (pseudo code):
if (action == START_FOREGROUND) {
...
startForeground(NOTIFICATION_ID, notification);
} else if (action == STOP_FOREGROUND) {
startForeground(NOTIFICATION_ID, closeNotification); //in case it wasn't started before
stopForeground(true);
stopSelf();
}
Even though it is not obvious, and any documentation don't directly say that when you need to stop foreground you need to start foreground before stopping it (if it wasn't started).
Thanks #Pawel for the hint.

Related

Foreground notification still appearing after Intent service destroyed

I have an IntentService and inside this instant service, in onCreate, I call the method startforeground(). I see then the notification when the intentService is created. However, when the IntentService is destroyed (going to onDestroy), I can see the notification for few seconds after that the service is destroyed. Why is that?
This is the code of the IntentService:
public class USFIntentService extends IntentService {
private static final String TAG = "USFIntentService";
private static final int USF_NOTIFICATION_ID = 262276;
private static final String USF_NOTIFICATION_CHANNEL_ID = "USF_NOTIFICATION_CHANNEL";
public USFIntentService() {
super("USFIntentService");
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG,"in onCreate");
startUsfForegroundService();
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG,"in onDestroy");
}
private void startUsfForegroundService() {
// Define notification channel
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel =
new NotificationChannel(USF_NOTIFICATION_CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
// Build notification to be used for the foreground service.
Notification notification =
new Notification.Builder(this, USF_NOTIFICATION_CHANNEL_ID)
.setContentTitle(getText(R.string.notification_title))
.setContentText(getText(R.string.notification_message))
.setSmallIcon(R.drawable.usf_notification_icon)
.build();
// Set the service as a foreground service.
startForeground(USF_NOTIFICATION_ID, notification);
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "onHandleIntent");
if (intent != null) {
doStuff();
}
Log.i(TAG,"End of onHandleIntent");
}
}
I call this service like this:
Intent startServiceIntent = new Intent(intent);
startServiceIntent.setComponent(new ComponentName(context, USFIntentService.class));
context.startForegroundService(startServiceIntent);
Try to call Service#stopForeground after your job is done to remove it
You can call stopForeground(true) when you finish doing the stuff. So that your service gets immediately removed from foreground state and the parameter true ensures that the notification will be removed.
If STOP_FOREGROUND_REMOVE is supplied, the service's associated notification will be cancelled immediately.
If STOP_FOREGROUND_DETACH is supplied, the service's association with the notification will be severed. If the notification had not yet been shown, due to foreground-service notification deferral policy, it is immediately posted when stopForeground(STOP_FOREGROUND_DETACH) is called. In all cases, the notification remains shown even after this service is stopped fully and destroyed.
stopForeground(STOP_FOREGROUND_REMOVE) // remove with notification
stopForeground(STOP_FOREGROUND_DETACH) // remove only intent and not notification

Foreground Service getting Crashed and restart when User killed the app (Nougat)

I am facing a trouble here where i want a foreground service should run untill its task get completed and once task get completed foreground service should stop. But the problem here is even if its Foreground Service the Service is getting killed when user close the app only in Nougat Version. I have checked Marshamallow,Oreo, Android pie version the scenario is working fine. But In Nougat and MI phone this scenario is not working correctly.
Below is Service code which i am running as a demo
public class MyForeGroundService extends Service {
private static final String TAG_FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
public static final String ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE";
public static final String ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE";
public static final String PRIMARY_CHANNEL = "default";
public MyForeGroundService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG_FOREGROUND_SERVICE, "My foreground service onCreate().");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null)
{
String action = intent.getAction();
switch (action)
{
case ACTION_START_FOREGROUND_SERVICE:
startForegroundService();
Toast.makeText(getApplicationContext(), "Foreground service is started.", Toast.LENGTH_LONG).show();
break;
case ACTION_STOP_FOREGROUND_SERVICE:
stopForegroundService();
Toast.makeText(getApplicationContext(), "Foreground service is stopped.", Toast.LENGTH_LONG).show();
break;
}
}
return super.onStartCommand(intent, flags, startId);
}
/* Used to build and start foreground service. */
private void startForegroundService()
{
NotificationCompat.Builder mBuilder = notificationBuilder();
// Start foreground service.
startForeground(1, mBuilder.build());
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent();
intent.setAction("SERVICE_CONNECTED");
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
},10000);
}
private void stopForegroundService()
{
Log.d(TAG_FOREGROUND_SERVICE, "Stop foreground service.");
// Stop foreground service and remove the notification.
stopForeground(true);
// Stop the foreground service.
stopSelf();
}
public NotificationCompat.Builder notificationBuilder(){
NotificationCompat.Builder mBuilder= new NotificationCompat.Builder(this, PRIMARY_CHANNEL)
.setContentTitle("Dummy Title")
.setContentText("Dummy Message")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Big text Message"
))
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mBuilder.setSmallIcon(R.drawable.app_icon_white);
mBuilder.setColor(getResources().getColor(R.color.theme_color));
} else {
mBuilder.setSmallIcon(R.drawable.app_icon_white);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getResources().getString(R.string.feroz_channel_name);
String description = getResources().getString(R.string.feroz_channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(PRIMARY_CHANNEL, name, importance);
channel.enableLights(true);
channel.setLightColor(getResources().getColor(R.color.theme_color));
channel.enableVibration(true);
channel.setDescription(description);
NotificationManager notificationManager1 = getSystemService(NotificationManager.class);
notificationManager1.createNotificationChannel(channel);
}
Intent stopIntent = new Intent(this, MyForeGroundService.class);
stopIntent.setAction(ACTION_STOP_FOREGROUND_SERVICE);
PendingIntent stopPlayIntent = PendingIntent.getService(this, 0, stopIntent, 0);
mBuilder.addAction(R.drawable.ic_launcher_new,"STOP",stopPlayIntent);
Intent intent = new Intent(this, CreateForegroundServiceActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
mBuilder.setUsesChronometer(true);
return mBuilder;
}
}
Below is code which start the service from activity
startServiceButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(CreateForegroundServiceActivity.this, MyForeGroundService.class);
intent.setAction(MyForeGroundService.ACTION_START_FOREGROUND_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
}
});
Button stopServiceButton = (Button)findViewById(R.id.stop_foreground_service_button);
stopServiceButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(CreateForegroundServiceActivity.this, MyForeGroundService.class);
intent.setAction(MyForeGroundService.ACTION_STOP_FOREGROUND_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
}
});
I think startForeGroundService works well but startService is not working as expected. The behaviour is so confusing, When i kill the app foreground service gets restarted , but if i open the app and press a button to stop the service i can see intent sent to the Service. But still the service is running.
PS: I want a service which run for like 10 Mins irrespective of App is in Background or not. It shouldn't get Restarted at any cost. For e.g if i am playing a music from background its should play till end. it should stop as soon as music ended. I dont want it to be restart
Below is logs when i start the service on button click and killed the app :
2019-02-15 13:35:56.091 11120-11120/sample.androido.com.myapplication D/MyForeGroundService: My foreground service onCreate().
2019-02-15 13:36:01.956 1459-3975/? W/ActivityManager: Scheduling restart of crashed service sample.androido.com.myapplication/.services.MyForeGroundService in 1000ms
2019-02-15 13:36:02.975 1459-1509/? I/ActivityManager: Start proc 11170:sample.androido.com.myapplication/u0a154 for service sample.androido.com.myapplication/.services.MyForeGroundService
2019-02-15 13:36:03.674 11170-11170/? D/MyForeGroundService: My foreground service onCreate().
From the official Android documentation for startForegroundService() method.
Note that calling this method does not put the service in the started state itself, even though the name sounds like it. You must always call ContextWrapper.startService(Intent) first to tell the system it should keep the service running, and then use this method to tell it to keep it running harder.
According to the above statement, you should call startService() first and then startForegroundService()

Worker-Thread ends prematurely

I am targeting Oreo. As you know, oreo introduced limits on background task execution time. Workarounds are - according to google - to put the background task in the foreground. This is what I was trying to do, yet once the foreground service is running, it gets destroyed after some time.
First the phone switches off it's screen, then once I activate it again, the background task continues. Sometimes onDestroy on the foreground service is called without the task being completed.
My goal is to have all tasks being set by enqueueWork to be executed without ondestroy being called and without phone sleep mode to interrupt it.
ForeGroundService
public class ForeGroundService extends JobIntentService {
static final int JOB_ID = 1000;
static final int ONGOING_NOTIFICATION_ID = 33;
static void enqueueWork(Context context, Intent work) {
enqueueWork(context, ForeGroundService.class, JOB_ID, work);
}
Notification.Builder notification;
NotificationManager mNotificationManager;
#RequiresApi(api = Build.VERSION_CODES.O)
void einleitung(String Titel, String Text)
{
Intent notificationIntent = new Intent(this, ForeGroundService.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(Titel,
Text,
NotificationManager.IMPORTANCE_HIGH);
channel.setSound(null,null);
mNotificationManager.createNotificationChannel(channel);
}
notification =
new Notification.Builder(this,Titel)
.setContentTitle(Titel)
.setContentText(Text)
.setSmallIcon(R.drawable.kleinesicon)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pendingIntent)
.setTicker("setTicker");
mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification.build());
startForeground(ONGOING_NOTIFICATION_ID, notification.build());
}
#RequiresApi(api = Build.VERSION_CODES.O)
void vordergrund(String Titel, String Text)
{
notification.setContentTitle(Titel);
notification.setContentText(Text);
mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification.build());
}
PowerManager.WakeLock wakeLock;
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
protected void onHandleWork(Intent intent) {
if (beginn) {
einleitung("Test", "Test");
beginn = false;
}
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakelockTag");
wakeLock.acquire();
//Do Work
}
#Override
public void onDestroy() {
super.onDestroy();
Intent local = new Intent();
local.setAction("de.test.action");
this.sendBroadcast(local);
stopForeground(true);
//toast("Fertig");
if (wakeLock != null)
wakeLock.release();
}
final Handler mHandler = new Handler();
}
MainActivity
public class MainActivity extends AppCompatActivity {
private int JI = 1000;
private BroadcastReceiver updateUIReciver;
#RequiresApi(api = Build.VERSION_CODES.O)
void somefunction(someparameters)
{
Intent mServiceIntent = new Intent();
mServiceIntent.putExtra...
ForeGroundService.enqueueWork(getBaseContext(),ForeGroundService.class,JI,mServiceIntent);
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(updateUIReciver);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter();
filter.addAction("de.test.action");
updateUIReciver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
ForeGroundService.shouldContinue = false;
}
};
registerReceiver(updateUIReciver,filter);
btnB.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.O)
public void onClick(View v) {
if (startcondition)
{
Intent startIntent = new Intent(MainActivity.this, MyService.class);
startIntent.setAction(Constants.ACTION.START_ACTION);
startService(startIntent);
Intent serviceIntent = new Intent(MainActivity.this,ForeGroundService.class);
startForegroundService(serviceIntent);
somefunction(someparameters);
}
else
{
Intent stopIntent = new Intent(MainActivity.this, MyService.class);
stopIntent.setAction(Constants.ACTION.STOP_ACTION);
startService(stopIntent);
}
}
});
}
}
EDIT: I made it work with sandhya sasane's solution and
public int onStartCommand(Intent intent, int flags, int startId)
{
if (beginn) {
executorService = Executors.newFixedThreadPool(1);
beginn = false;
}
final Intent i2 = intent;
executorService.execute(new Runnable(){
#Override
public void run(){
abarbeiten(i2);
}
});
return START_STICKY;
}
Important is the 1 in newFixedThreadPool(1); to only have one thread run at once
I am targeting Oreo. As you know, oreo introduced limits on background task execution time.
Yes, it does. I can understand you, as google has made the things very odd and complex first..., then again complicated... then again... then again... And now developers like me and you, and your question and problem, denotes the outcome / result / proof of that.
Workarounds are - according to google ...
Please save time and yourself too... Google documentation is worst.. i have given -10 out of 10 for their documentation.
to put the background task in the foreground.
You have a wrong perception of what foreground concept is..!! Read complete answer word by word carefully, Your problem will get solved..!!
This is what I was trying to do, yet once the foreground service is running, it gets destroyed after some time...
Now very simply... Your Concept and implementation, both are wrong..., So Try with a new sample project and guidelines provided here along with sample working and tested code across 4.0 to latest android P
.
First the phone switches off it's screen, then once I activate it again, the background task continues. Sometimes onDestroy on the foreground service is called without the task being completed.
It does not relate to foreground service, in any way.... forget this.
My goal is to have all tasks being set by enqueueWork to be executed without ondestroy being called and without phone sleep mode to interrupt it.
Forget this too... Lets first see what a foreground service is and how it is created...
What is foreground service
A service which remains active (It does not mean... continuously
running like never ending do-while loop)
Remain active until next boot / reboot
Even if user removes app from recents, it remains
But It does not remain active post next boot
It needs to be restarted by user by opening app again or via a broadcast receiver of ON_BOOT_COMPLETE or by a AlarmManager or By a JobScedular
When to use
As per my view users do not like a permanent notification showing message ^This is running in foreground and may discharge your battery soon^ , Again user would not be able to swipe it away and can only force stop or uninstall app to stop it. So it is as per my implementations point of view , ^Developers must use this for implementing runtime receivers as post - oreo devices do not welcomes static receivers implemented by extending Broadcastreceiver and placing its intent entry in manifest.xml file... Even if developer tries to do this that receiver will never get called on post - oreo devices ..., Yes it will get called below oreo devices. So implement just a ON_BOOT_COMPLETE receiver and rest all in a service.
How to implement a foreground service
Right click on project structure and make a service named RunnerService and then generate all mandatory methods. it does not require you to type all code manually.. Generate it as said. Sample foreground service :
public class RunnerService extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "1";
public RunnerService() { }
#Override
public void onCreate()
{
super.onCreate();
Log.d("RUNNER : ", "PROGRAMMED.... \n");
Bitmap IconLg = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("App Name")
.setContentText("Foreground service...")
.setTicker("Foreground service...")
.setSmallIcon(R.drawable.ic_menu_slideshow)
.setLargeIcon(IconLg)
.setPriority(Notification.PRIORITY_HIGH)
.setVibrate(new long[] {100})
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setOngoing(true)
.setAutoCancel(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{100});
notificationChannel.enableVibration(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotifyManager.createNotificationChannel(notificationChannel);
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(1, mBuilder.build());
}
else
{
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
mNotifyManager.notify(1, mBuilder.build());
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("RUNNER : ", "\n IT IS ACTIVE UNTIL NEXT BOOT....");
return START_STICKY;
}
#Override
public void onDestroy()
{
Log.d("RUNNER : ", "\n IT WILL BE AGAIN ACTIVE BY ANDROID OS AUTOMATICALLY, DO NOT WORRY AND DONT CODE TO START IT AGAIN !!....");
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent)
{
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("NOT_YET_IMPLEMENTED_BY_DEVELOPER");
}
}
How to start it
It depends on which android you are targeting below oreo or post oreo ... I will prefer to on all like below :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
this.startForegroundService(new Intent(this, RunnerService.class));
}
else
{
this.startService(new Intent(this, RunnerService.class));
}
Either from MainActivity or any ON_BOOT_RECEIVER, or from wherever you want, just start it as said here...
How to test is in foreground
By removing it from recents... It will call onDestroy but it will be never destroyed you will not be able to swipe away notification. This means a success.
How to test it quick
With a sample new project with a MainActivity just calling service in said manner.
What next..?
Yes you can ask your next tasks here only..., I will keep updating and guiding... I hope you have kept enqueueWork concept and all your concepts aside and do not thinking on it...
Lets go step by step and let me know the updates....
UPDATE 2
You should try it on emulator only... If success then try it on actual devices... Here is a problem again...
There are many mobile phone manufacturers in the world now, which takes
stock android from google as it is open source and modifies it to disable all services on BOOT. It only keeps Google , WhatsApp, FaceBook , Twitter and major market leaders... As if they do not allow them no one will purchase their devices ...
Examples :
Vivo = FunTouchOs
Oppo = ColorOs
There is a huge list....
Do not check on this for BOOT_COMPLETE..., IT will not work as they are modified the android..
But i want to test it on actual device
Then test it on such device which os is purely from google and having android os.
Then what should i do for other os modified from android
There are tricks ..., But lets go step by step.... I will let you know , once you success in this..!!
UPDATE : 3
As it is not clear what is the requirement i am making some assumptions and writing answer :
What you can do to implement foreground execution is :
Implement foreground service as i depicted
Use local broadcastmanager to broadcast events of your own.
in onCreate of a foreground service register runtime receiver to receive that broadcasts
On receiving broadcasts call to the methods of user defined class with context of foreground service. And perform all tasks from there.
Unregister receiver from onDestroy of foreground service.
What you can do to implement background execution is :
If you are having repeating tasks and wants to execute it in background even if the app is removed from recents ... Then :
Use Firebase Job Dispatcher which uses GooglePLAYServices
If you use forever then that job will be triggered automatically even if system is rebooted and even if app is not in foreground or background or in recents...
As of now i do not see any need of JobIntentService and therefore its static enqueueWork method; More resolution and details are needed for solving your problem.

Background service is not working in Oreo

I want to run my app in background if I kill the app instance also. But after I kill my app the service also stops working. Here is my code please any one help me to solve my issue.
I followed this link for running in the background but it is not working if I remove the instance. Please can any one show me how to run a background service if the instance is removed also?
This is my MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
setContentView(R.layout.activity_main);
Intent alarmIntent = new Intent(MainActivity.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, ALARM_REQUEST_CODE, alarmIntent, 0);
mSensorService = new SensorService(getCtx());
mServiceIntent = new Intent(getCtx(), mSensorService.getClass());
if (!isMyServiceRunning(mSensorService.getClass())) {
startService(mServiceIntent);
}
}
Ths is my service class
public class SensorService extends Service{
public int counter=0;
public SensorService(Context applicationContext) {
super();
Log.i("HERE", "here I am!");
}
public SensorService() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startTimer();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i("EXIT", "ondestroy!");
Intent broadcastIntent = new Intent("uk.ac.shef.oak.ActivityRecognition.RestartSensor");
sendBroadcast(broadcastIntent);
}
private Timer timer;
private TimerTask timerTask;
long oldTime=0;
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, to wake up every 1 second
timer.schedule(timerTask, 1000, 1000); //
}
/**
* it sets the timer to print the counter every x seconds
*/
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
Log.i("in timer", "in timer ++++ "+ (counter++));
}
};
}
/**
* not needed
*/
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Its a long story. I have gone through it. Still implemented it. Now my service runs on every boot_complete event and keeps running all the time ( with a notification ).
Official Documentation:
Big NO. Google android developer documentation is poor, with no proper sample example too. It is theoretical and just theoretical. Keep reading if interested
https://developer.android.com/about/versions/oreo/background
Synopsis 1:
You can only receive BOOT_COMPLETE and only few broadcasts in traditional receiver. Rest all broadcast receivers you need to implement runtime in a service by registering them through a code from service which always runs.
Synopsis 2:
Again, you can not have always running processes in or above 8.0 (Oreo)...
To achieve always running process... Create a Intentservice with proper notification of type ongoing and make OnStartCommand START_STICKY and register receiver with code in OnCreate
How to implement it :
I have implemented it take reference from here :
Oreo: Broadcast receiver Not working
Now Your Question : I want to run my app in background if it kills the
app instance also.
With the help of above implementation link of my own you can achieve it
*Terms and conditions
You device must have proper android operating system released and burnt as it is.
Yes, I am using android :
No... You are Using Funtouch OS : VIVO ( By modifying Android)
There are many devices in market COLOR OS : OPPO ( By modifying Android)
....
....
Already google has made it complicated... version by version....
With no proper documentation and sample codes....
And Now Independent mobile device manufacturers making a lot of
changes to allow only selective applications run in background
like WhatsApp, Facebook, Google Twitter Instagram
Now you will ask a developer question If these app runs in background then I can make my app run in background too....
No... They are OS based modifications to check if a service is from allowed vendors then only it can be alive there in background. If they will not allow these vendors then no one take phones which does not run these famous social apps.
Hushhhhhhhh.......
You need to create ForegroundService in order continue processing when your app is killed, as follows:
public class SensorService extends Service{
private PowerManager.WakeLock wakeLock;
#Override
public void onCreate() {
super.onCreate();
//wake lock is need to keep timer alive when device goes to sleep mode
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK_TAG");
createNotificationChannel(this);
Notification notification = new NotificationCompat.Builder(this, "NOTIFICATION_CHANNEL").setSmallIcon
(<icon>).setContentTitle("Title")
.setContentText("Content").build();
startForeground(1001, notification);
}
#Override
public void onDestroy() {
super.onDestroy();
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
public void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Channel name";
String description = "Description";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("NOTIFICATION_CHANNEL", name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getApplicationContext().getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
To start the service:
Intent i = new Intent(context, SensorService.class);
ContextCompat.startForegroundService(context, i)
Note:
You cannot run service endlessly with this approach. During doze mode if OS recognizes it as CPU intensive then your Service will be terminated.
You need to call stopSelf() when your Timer task has been executed successfully.
Oreo Introduced
new Concept PIP (Picture in Picture Mode )
and it have categories services control by making channels and priority to them.you have to change the code just for oreo to create notifications and services
read about google developers documentation carefully here
https://developer.android.com/guide/topics/ui/notifiers/notifications
both java and kotlin code is available here to create notification in oreo
https://developer.android.com/training/notify-user/build-notification
it was my effort to find the solution after searching and sharing with you.
here is some sample code :
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Much longer text that cannot fit one line...")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Much longer text that cannot fit one line..."))
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
for creating channels write this code:
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
you can see full detials for push notifications and sending messages by clicking on the above links.

Cannot keep android service alive after app is closed

I am trying to spawn a service that stays alive all the time, even if the user closes the application. According to these threads
Keep location service alive when the app is closed
Android Service Stops When App Is Closed
Android: keep Service running when app is killed
this can be accomplished with IntentServices or Service.START_STICKY
Yet, I tried both types of services without success. In other words, my services get killed when the app is closed by the user. Can someone point out if this is can be done and how? Here is what I have tried without success:
With IntentService:
public class MyIntentService extends IntentService {
private final int mPollingTimeMS = 500;
private int mInitializationPollingCount = 0;
private Thread mPollThread;
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
mPollThread = new Thread() {
public void run() {
while (true) {
try {
Log.e(Constants.Engine.LOGGER_TAG_DEV,
"SDK Service Running: " +
mInitializationPollingCount * mPollingTimeMS +
"ms have elapsed");
mInitializationPollingCount++;
sleep(mPollingTimeMS);
} catch (Exception e) {
StackTraceElement trace = new Exception().getStackTrace()[0];
Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
}
}
}
};
mPollThread.start();
}
}
and with Services:
public class MyService extends Service {
public MyService() {
}
private final int mPollingTimeMS = 500;
private int mInitializationPollingCount = 0;
private Thread mPollThread;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mPollThread = new Thread() {
public void run() {
while (true) {
try {
Log.e(Constants.Engine.LOGGER_TAG_DEV,
"SDK Service Running: " +
mInitializationPollingCount * mPollingTimeMS +
"ms have elapsed");
mInitializationPollingCount++;
sleep(mPollingTimeMS);
} catch (Exception e) {
StackTraceElement trace = new Exception().getStackTrace()[0];
Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
}
}
}
};
mPollThread.start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// I tried to return null here, but this
// service gets killed no matter what.
return null;
}
}
and here is the manifest:
<service
android:name=".mycompany.MyService"
android:enabled="true"
android:exported="true"
android:process=":process1">
</service>
<service
android:name=".mycompany.MyIntentService"
android:process=":process2"
android:exported="false">
</service>
I shall added that I am closing the test app not with a close button, but using the Android OS app manager. See picture below
Lastly, the driver activity (not much there)
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent1 = new Intent(getBaseContext(), MyService.class);
startService(intent1);
Intent intent2 = new Intent(getBaseContext(), MyIntentService.class);
startService(intent2);
}
}
I also try to add a notification and make it a foreground service but still the same thing. The moment I close the app, everything gets killed. This is what I added:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
showNotification();
...etc..
private void showNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
int iconId = R.mipmap.ic_launcher;
int uniqueCode = new Random().nextInt(Integer.MAX_VALUE);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(iconId)
.setContentText("Context Text")
.setContentIntent(pendingIntent).build();
startForeground(uniqueCode, notification);
}
Here is an example of foreground service that I use and that works, it remains active when the app is closed. Of course, it also must be started, and for that task the app must be running at a first glance, or a receiver of a boot event must be set, but this is another story.
public class MyService extends Service {
static final int NOTIFICATION_ID = 543;
public static boolean isServiceRunning = false;
#Override
public void onCreate() {
super.onCreate();
startServiceWithNotification();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction().equals(C.ACTION_START_SERVICE)) {
startServiceWithNotification();
}
else stopMyService();
return START_STICKY;
}
// In case the service is deleted or crashes some how
#Override
public void onDestroy() {
isServiceRunning = false;
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// Used only in case of bound services.
return null;
}
void startServiceWithNotification() {
if (isServiceRunning) return;
isServiceRunning = true;
Intent notificationIntent = new Intent(getApplicationContext(), MyActivity.class);
notificationIntent.setAction(C.ACTION_MAIN); // A string containing the action name
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent contentPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.my_icon);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(getResources().getString(R.string.app_name))
.setTicker(getResources().getString(R.string.app_name))
.setContentText(getResources().getString(R.string.my_string))
.setSmallIcon(R.drawable.my_icon)
.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(contentPendingIntent)
.setOngoing(true)
// .setDeleteIntent(contentPendingIntent) // if needed
.build();
notification.flags = notification.flags | Notification.FLAG_NO_CLEAR; // NO_CLEAR makes the notification stay when the user performs a "delete all" command
startForeground(NOTIFICATION_ID, notification);
}
void stopMyService() {
stopForeground(true);
stopSelf();
isServiceRunning = false;
}
}
Then I run it with
Intent startIntent = new Intent(getApplicationContext(), MyService.class);
startIntent.setAction(C.ACTION_START_SERVICE);
startService(startIntent);
Please note the two constants used as Actions, these are Strings that must start with the package name.
IntentService
Using IntentService is probably not the best approach. By default IntentService stops itself after onHandleIntent(Intent) returns and there's no work left to do (i.e. the request queue is empty). This is explained in the official docs of IntentService:
When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().
In your case, onHandleIntent(Intent) creates a thread but returns right away, which makes it stop by itself.
Service + startForeground()
Using a regular Service in foreground mode should work as long as you keep that service running on a separate process. For that, you need:
Make the onStartCommand() return START_STICKY.
Call the method to show the notification right in onCreate().
Run the service in a separate process (using android:process=":something").
Based on the post, it seems that you've tried some of these steps in isolation but never tried all of them at the same time.
If none of the answers above are working, maybe it is a manufacturer specific issue. Some MI phones, for instance, kill the foreground service when the user kill the app via task manager.
I recommend you to test the app on a virtual device, so you can check if it is or isn't this kind of issue.
Hope it helps!
You can simply call your service in your onStop() method inside your activity.
Even when user stops the app the service will still be running.
Try the answers for this similar question: Bad notification for startForeground in Android app

Categories

Resources