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.
Related
I am developing an app where the app will detect Bluetooth signals (Sensoro Smart Beacon device) and open the activity. But I want the app to still be able to detect the signal even when the application on the background or even when killed. I used a foreground service, it detects the signal when I open the application and move between activities but when sending the app to the background and opening other applications, the listener stops although the service still working. I am printing the logs. System.out.println("Sensoro 2" ); keeps printing even when I kill the application or open another application. But the printing logs in BeaconManagerListener are not working. I tried to use background service but it didn't work also.
Can you please advise if there is a way to make the listener works in a service when the app in background or killed?
Here is the service code:
public class MyService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
int service_timer=0;
Timer timer = new Timer();
SensoroManager sensoroManager;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
sensoroManager = SensoroManager.getInstance(MyService.this);
String input = intent.getStringExtra("inputExtra");
System.out.println("Sensoro 2" );
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
.build();
startForeground(1,notification);
//do heavy work on a background thread
//stopSelf();
if (sensoroManager.isBluetoothEnabled()) {
sensoroManager.setCloudServiceEnable(true);
/**
* Enable SDK service
**/
try {
sensoroManager.startService();
} catch (Exception e) {
e.printStackTrace(); // Fetch abnormal info
}
}
else
{
Toast.makeText(MyService.this,"Bluetooth off",Toast.LENGTH_LONG).show();
}
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//your method
System.out.println("Sensoro 2" );
BeaconManagerListener beaconManagerListener = new BeaconManagerListener() {
#Override
public void onUpdateBeacon(ArrayList<Beacon> beacons) {
// Refresh sensor info
for (Beacon beacon : beacons
) {
System.out.println("Sensoro 3" );
// System.out.println("Sensoro" +beacon.getAccuracy());
}
}
#Override
public void onNewBeacon(Beacon beacon) {
if (beacon.getSerialNumber().equals("0117C59B243C")){
System.out.println("Sensoro 3" );
System.out.println("Sensoro acc" +beacon.getAccuracy());
}
}
#Override
public void onGoneBeacon(Beacon beacon) {
if (beacon.getSerialNumber().equals("0117C59B243C")){
System.out.println("Sensoro acc gone");
System.out.println("Sensoro acc Timer" +service_timer);
}
}
};
sensoroManager.setBeaconManagerListener(beaconManagerListener);
}
}, 0, 2000);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
// timer.cancel();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
Here is where I call it:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService();
}
public void startService() {
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("inputExtra", "Foreground Service Example in Android");
System.out.println("Sensoro 1 ");
ContextCompat.startForegroundService(this, serviceIntent);
}
public void stopService() {
Intent serviceIntent = new Intent(this, MyService2.class);
stopService(serviceIntent);
}
public void movingg(View view) {
Intent intent=new Intent(this,Usermain.class);
startActivity(intent); }
}
This is not 100% a match with what are you searching but this is near to what are you want.
You can use WorkManager that is working even application in the background. There are two types of WorkManager. 1) OneTimeWorkRequest 2) PeriodicWorkRequest.
So you can you PeriodicWorkRequest which will call every 15 min(minimum interval) and you can add your code in WorkManager to detect Bluetooth signals. So you can able to detect Bluetooth single at every 15 mins of intervals.
I hope this will help you solve your problem.
I don't know if this will help you, but here's my answer:
public void startService() {
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("inputExtra", "Foreground Service Example in Android");
System.out.println("Sensoro 1 ");
startService(serviceIntent);
}
I looked at the Android rules and regulations page
According to Google documents, from Android 8 onwards, all applications that do not have a Google-approved signature will be removed from the background after a few minutes.
But the solutions:
The first solution is to run the application in debug mode
The second solution is to assign a signature to the application and send it to Google for approval
recommend:
The third solution is to remove the google play service application from the emulator or android phone
you can use BroadcastReceiver.
if your app is killed or in the background ,the broadcast receiver is catch the event of bluetoth
I see there are two issues with your approach here.
First you should your check for specific beacon serial number could be causing issue.
Secondly you are using a Timer that goes off every 2 seconds and every time it does it adds a new BeaconManagerListener which should not be the case you should extract the listener outside maybe make it a class member and then use the same listener every time instead of continuously creating new listener which then replaces the old one.
Also why add listener after 2 seconds I think is should be added before calling sensoroManager.startService()
Lastly if the task is not needed to be repeated every few seconds and can be done with an interval >= 15 mins then consider using Periodic Work Manager instead.
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.
From the stackoverflow and many blogs, i surely understand that foreground service never run without notification in API>25. But still i confuse that Is notification mandory while app is running on screen or visible.
For eg. no need of notification when user stand within app. So is this possible to remove notification while app running ?
In service class
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
......
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText(text)
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(1, notification);
}
return START_NOT_STICKY;
}
In activity
Intent myService = new Intent(this, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(myService);
} else {
startService(myService);
}
It's not possible to remove the notification while the foreground service is running, but it is possible to change your foreground service back into a "regular" service. This removes the need for a notification. In fact, the function to use,
stopForeground(boolean removeNotification)
...includes a removeNotification parameter just for that purpose. You service can switch from being "foreground" to "regular" on demand, by alternating calls to startForeground() and stopForeground().
In case it's not clear, you'd probably want to call stopForeground() whenever you have at least one Activity in a "started" state. This is something you'd have to track manually. Then, when the number of "started" activities reaches 0, you'd call startForeground().
EDIT
One approach is to use a bound service. Then, it's easy to call stopForeground() on it when you want.
Assume you have a single Activity. You can bind it to the service (see this doc or use one of these examples). Then your onServiceConnected() function could look like this (adapted from the Google example):
//MyActivity.java:
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mService.stopForeground(true); //This makes the notification go away
bound = true;
}
...
#Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MyService.class), this, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (bound) {
Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText(text)
.setAutoCancel(true);
Notification notification = builder.build();
mService.startForeground(1, notification); //This brings the notification back! Service is already running, and continues to run.
unbindService(this);
bound = false;
}
}
No, it is mandatory even your app is running in foreground your foreground service need a notification.
You won't able to hide it.
Why :
You can use any other background task handler like intent service, job sclr but things is designed defferent for foreground service your user understand that event i will close this one of it's progress is going to keep running but things is defferent with background service your know it will do something in background but when system decide it's best time to do it not when your app want (as like in foreground service).
One more case ex :
Suppose your app in foreground battery level is lower than expected by user or system your foreground service will execute instantly no matter what so it's important for your user to know this it's running and take my resources (battery, data, etc)
Hopefully you got my mean 🙂
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.
I'm calling a service every three minutes using the following function:
public void RunBackgroundService() {
final Handler service_handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
service_handler.post(new Runnable() {
public void run() {
context.startService(new Intent(context,BackgroundService.class));
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 180 * 1000);
}
And this is my service in which I'm launching a notification:
public class BackgroundService extends Service {
Helper helper;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
//Toast.makeText(this, "Service created!", Toast.LENGTH_LONG).show();
}
#Override
public void onDestroy() {
//Toast.makeText(this, "Service stopped", Toast.LENGTH_LONG).show();
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onStart(Intent intent, int startid)
{
helper=new Helper(this);
// Log.d("Service started at:", helper.getdatetime());
Intent n_intent = new Intent(this, MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, n_intent, 0);
// build notification
// the addAction re-use the same intent to keep the example short
long[] vibrate = { 0, 100, 200, 300 };
Notification n = new Notification.Builder(this)
.setContentTitle("Application")
.setContentText("This is a test")
.setSmallIcon(R.drawable.notification_icon)
.setContentIntent(pIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setVibrate(vibrate)
.setAutoCancel(true)
.build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, n);
}
}
It's very important to me to remain the service running at all time, when the app crashes the service stops. How can I prevent the service from stopping ?
When an app crashes, the entire process goes down with it. This includes all Services and other threads in that process. You can't stop that from happening.
The best you can do is to configure your app to run in a different process from the main app process, but then you have to know how that affects the rest of your app.
Be sure to read the docs for how to define a service to run in another process. You use the android:process attribute for that.
You cna not stop system killing your service. But what you can do is to restart the service when it is crashed. Take a look at detailed sof post How to restart service after the app is killed from recent. This solution works not only when app is killed through recent taks by user but also when system kills app.
Use android:process tag to start process in different process.
Then use it as bind to service from your application, this way you can communicate with service via ipc and service runs indefinitely even if your app crashes.