I have a task to periodically read the phone sensors (e.g. WiFi, accelerometer) in the backend.
My current solution is to use an AlarmManager.
Specifically, we have:
In the "main" program (an activity), we use PendingIntent.getService:
public class Main extends Activity {
...
Intent intent = new Intent(this, AutoLogging.class);
mAlarmSender = PendingIntent.getService(this, 0, intent, 0);
am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, 0, 5*1000, mAlarmSender);
}
In the "AutoLogging" program (a service), we respond to the alarm periodically:
public class AutoLogging extends Service {
...
#Override
public void onCreate() {
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
}
#Override
public boolean onUnbind(Intent intent) {
Toast.makeText(this, "onUnbind", Toast.LENGTH_SHORT).show()
return super.onUnbind(intent);
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show();
// Read sensor data here
}
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(this, "onBind", Toast.LENGTH_SHORT).show();
return null;
}
}
My problem is:
When I use this alarm service, only OnCreate and OnStart are called at each alarm.
My questions are:
(1) Do we need to call OnDestroy (or onBind, onUnbind)?
(2) Is this a correct way to use AlarmManager (compared with "broadcase receiver")?
Thanks!
Vincent
AlarmManager just uses the pending intent and performs the intent action, i.e starting service in your case.On alarm expiry service is created using onCreate( if it is not already running ) and then started by calling onStart. After you finish reading the sensor data, you can stop the service using stopSelf() which will ultimately call onDestroy().You shouldn't call onDestroy(),onBind() or onUnBind() explicitly in the service.
If you use broadcast receiver with alarm manager you have to start this service in onReceive of receiver.Using Service seems appropriate to me in this case.
If you want to schedule a job in android periodically instead of using an alarm manager you can use GCM network manager with the periodic task. This internally uses an alarm manager or job scheduler depending on the Android version. It is also easier to use with a more flexible option.
This article is great -
https://www.bignerdranch.com/blog/optimize-battery-life-with-androids-gcm-network-manager/
Chiming in years late for anyone that stumbles upon this.
In terms of which method gets called when for services see this post here:
Android onCreate or onStartCommand for starting service
You'd want to trigger in the onStartCommand.
Related
I have an issue to use service.
I am trying to use background service with permanently running. I have implemented with AlarmManager. So when app closed then send broadcast in service's OnDestroy() method. And in alarm receiver, can start service.
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
serviceInstance = this;
callHelper = new CallHelper(this);
callHelper.start();
return START_STICKY;
}
#Override
public void onDestroy() {
Log.d("1111111111", "stop service");
super.onDestroy();
setAlarmTimer();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.d("1111111111", "stop remove");
super.onTaskRemoved(rootIntent);
}
protected void setAlarmTimer() {
final Calendar c = Calendar.getInstance();
c.setTimeInMillis(System.currentTimeMillis());
c.add(Calendar.SECOND, 1);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(this, 0,intent,0);
AlarmManager mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), sender);
}
But if I remove(swipe) the app from recent app list, then service's OnDestroy() or OnTaskRemoved doesn't called. So can't call AlarmManager.
Following is my Manifest.xml:
<service
android:name=".service.CallTrackService"
android:enabled="true"
android:exported="true"
android:stopWithTask="false"/>
How to call service's OnDestory() or OnTaskRemoved() method when removing the app from recent app list?
Anyone who know this issue then please provide a solution.
The Service class has an onTaskRemoved() method which is triggered when the app is removed from the recent apps.
There the Service can call stopSelf() to shut itself down.
As in:
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
stopSelf();
}
edit
in android Oreo , start your service this way :
startForegroundService(new Intent(context, your_service.class));
You don't. The framework does. A bound service is destroyed when nothing is bound to it anymore. A started service is destroyed when its explicitly stopped, or when the system needs resources. To explicitly stop a service, call stopService from any Context, or stopSelf from the Service.
But "I am trying to use background service with permanently running.". Not possible in modern Android. The system will clean you up for resources. There is no way to make it permanently run, or even pseudo permanently with gaps via an alarm. Whatever it is you want your service to actually do, you need to find another way.
Description of Truecaller/Whatsapp service
**Note: Here force close means killing the app by pressing and holding back button not just stopping the service from service manager/app manager (see Kill app back button).
After killing the truecaller app when I make a call it restarts automatically, same for whatsapp also, After killing it when a message is received it still shows the notification and restarts the service. These services also restarts after a few delay
What I have done so far to achieve this
I want to make a service like this so called my backgroundservice from onDestroy() of my backgroundservice class. Code for this: ServiceDemo 0.1
public class BackgroundService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(BackgroundService.this, "Service Started...", Toast.LENGTH_SHORT).show();
return START_STICKY;
}
#Override
public void onDestroy() {
Intent intentService = new Intent(this,BackgroundService.class);
startService(intentService);
Toast.makeText(BackgroundService.this, "Service Will Be Restarted...", Toast.LENGTH_SHORT).show();
}
}
The service is restarting if I stop it from my service manager. But if I force close/kill it , it's gone.
After this I implemented Broadcast receiver which doesn't make any difference. Code for this: ServiceDemo 0.2
BackgroundService.java
public class BackgroundService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(BackgroundService.this, "Service Started...", Toast.LENGTH_SHORT).show();
return START_STICKY;
}
#Override
public void onDestroy() {
Toast.makeText(BackgroundService.this, "Service Will Be Restarted...", Toast.LENGTH_SHORT).show();
sendBroadcast(new Intent("RestartMe"));
}
}
RestartBackgroundService.java
public class RestartBackgroundService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// I have also used AlarmManager , but it doesn't make any difference for me
// AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// PendingIntent pi = PendingIntent.getService(context, 0, new Intent(context, BackgroundService.class), PendingIntent.FLAG_UPDATE_CURRENT);
// int interval = 5000;
// am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + interval, interval, pi);
context.startService(new Intent(context.getApplicationContext(),BackgroundService.class));
}
}
As whatsapp is using gcm so I thought if I implement that it would help.
Then I implemented firebase cloud messaging (fcm) to receive push notification and I removed the code to restart background service from onDestroy().
Now if I stops the service from service manager it remains stopped then I sends a notification from my firebase console it receives the notification as google's gcm service is running. If I click the notification it restarts my service again.
But if I force close/kill my app no notifications are received though gcm service is running. Code for this: (I posted a link to make the description a bit short)
ServiceDemo 0.3
What I want
I want my service to be persistent like whatsapp/truecaller even if I force close it. They keep on starting after a few delays. And I want to achieve it without using third parties like fcm.
If someone can give any hints/solution about how to start my service when a particular system service/app (like dialer) starts that would be a great help.
I want to make a service in android which run in background always and start as soon as I boot my phone and send message at a regular interval.I have writen my code as below
MainActivity.class
package test.sai;
public class MainActivity extends Activity {
Timer t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
alrm();
Log.e("msg", "in main");
}
public void alrm() {
Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class);
Log.e("msg", "in alrm");
//myAlarm.putExtra("project_id", project_id); //Put Extra if needed
PendingIntent recurringAlarm = v PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Calendar updateTime = Calendar.getInstance();
Log.e("msg", "in alrm1");
//updateTime.setWhatever(0);
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, recurringAlarm); //you can modify the interval of course
}
}
This class is calling AlarmReceiver.class
package test.sai;
public class AlarmReceiver extends BroadcastReceiver
{
GPSTracker gps;
#Override
public void onReceive(Context context, Intent intent)
{
gps = new GPSTracker(context);
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent pushIntent = new Intent(context,MainActivity.class);
pushIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(pushIntent);
Log.e("pro", "alrmmanager");
}
Intent myService = new Intent(context, FirstService.class);
myService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(myService);
Log.e("msg", "in alrmmanager1");
}
}
and finally AlarmReceiver is calling the service class
package test.sai;
public class FirstService extends Service{
Timer t;
int time = 0;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onStart(Intent intent, int startId) {
Log.e("time", time++ +"");
Toast.makeText(this, time+1+"", 500).show();
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
Now I want to on GPS as soon as service starts and then I want to use GPS to track location of mobile and send a message to another mobile.I also have code for GPS and sms sending but I am not getting how to call and where to call those methodss,so that my service keep on running and sending messages at some perticular interval.please help.
You can use alarmManager for this... Because if you create your own timerTask, it is very much susceptible to get destroyed by the processor.
To answer your two part question:
First you need to learn how to handle onBoot within Android Framework. Refer to this Q/A Trying to start a service on boot on Android
Lastly you need to understand the SMSManager class. Refer to the documentation http://developer.android.com/reference/android/telephony/SmsManager.html
I don't think anyone should provide complete code for your request as your main problem/question is "How can I help myself and stop looking for others to fix all my problems".
Try registering a BroadcastReceiver with AlarmManager to receive an intent at your regular interval. You'll probably want two, one that listens for a BOOT_COMPLETED action, and another that the AlarmManager will start on interval. You can have the second receiver start a service if whatever you want to do will take a while to execute.
Here's a question on how to make the receiver run on boot so you can register the other receiver with AlarmManager:
Android BroadcastReceiver on startup
Here's another that wants pretty much the same thing you want, minus the SMS:
How to Autostart an AlarmManager to start a Scheduled Activity?
I am working on an app that will relay information about its location to a remote server. I am intending to do it by doing a simple HTTP post to the web-server and all is simple and fine.
But according to the spec, the app needs to execute itself from time to time, lets say once in every 30 mins. Be independent of the interface, meaning which it needs to run even if the app is closed.
I looked around and found out that Android Services is what needs to be used. What could I use to implement such a system. Will the service (or other mechanism) restart when the phone restarts?
Thanks in advance.
Create a Service to send your information to your server. Presumably, you've got that under control.
Your Service should be started by an alarm triggered by the AlarmManager, where you can specify an interval. Unless you have to report your data exactly every 30 minutes, you probably want the inexact alarm so you can save some battery life.
Finally, you can register your app to get the bootup broadcast by setting up a BroadcastReceiver like so:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
// Register your reporting alarms here.
}
}
}
You'll need to add the following permission to your AndroidManifest.xml for that to work. Don't forget to register your alarms when you run the app normally, or they'll only be registered when the device boots up.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Here is a semi-different way to keep the service going forever. There is ways to kill it in code if you'd wish
Background Service:
package com.ex.ample;
import android.app.Service;
import android.content.*;
import android.os.*;
import android.widget.Toast;
public class BackgroundService extends Service {
public Context context = this;
public Handler handler = null;
public static Runnable runnable = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service created!", Toast.LENGTH_LONG).show();
handler = new Handler();
runnable = new Runnable() {
public void run() {
Toast.makeText(context, "Service is still running", Toast.LENGTH_LONG).show();
handler.postDelayed(runnable, 10000);
}
};
handler.postDelayed(runnable, 15000);
}
#Override
public void onDestroy() {
/* IF YOU WANT THIS SERVICE KILLED WITH THE APP THEN UNCOMMENT THE FOLLOWING LINE */
//handler.removeCallbacks(runnable);
Toast.makeText(this, "Service stopped", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show();
}
}
Here is how you start it from your main activity or wherever you wish:
startService(new Intent(this, BackgroundService.class));
onDestroy() will get called when the application gets closed or killed but the runnable just starts it right back up.
I hope this helps someone out.
The reason why some people do this is because of corporate applications where in some instances the users/employees must not be able to stop certain things :)
http://i.imgur.com/1vCnYJW.png
EDIT
Since Android O (8.0) you have to use JobManager for scheduled tasks. There is a library called Android-Job by Evernote which will make periodic background work a breeze on all Android versions. I have also made a Xamarin Binding of this library.
Then all you need to do is the following:
In your application class:
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new MyJobCreator());
}
}
Create the following two classes YourJobCreator and YourSyncJob(Where all the work will be done. Android allocates time for all the background jobs to be run. For android versions < 8.0 it will still run with an Alarm manager and background service as per normal)
public class MyJobCreator implements JobCreator {
#Override
#Nullable
public Job create(#NonNull String tag) {
switch (tag) {
case MySyncJob.TAG:
return new MySyncJob();
default:
return null;
}
}
}
public class MySyncJob extends Job {
public static final String TAG = "my_job_tag";
#Override
#NonNull
protected Result onRunJob(Params params) {
//
// run your job here
//
//
return Result.SUCCESS;
}
public static void scheduleJob() {
new JobRequest.Builder(MySyncJob.TAG)
.setExecutionWindow(30_000L, 40_000L) //Every 30 seconds for 40 seconds
.build()
.schedule();
}
}
You should schedule your service with alarm manager, first create the pending intent of service:
Intent ii = new Intent(getApplicationContext(), MyService.class);
PendingIntent pii = PendingIntent.getService(getApplicationContext(), 2222, ii,
PendingIntent.FLAG_CANCEL_CURRENT);
Then schedule it using alarm manager:
//getting current time and add 5 seconds to it
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
//registering our pending intent with alarmmanager
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), pi);
this will launch your service after 5 seconds of current time. You can make your alarm repeating.
You can use Alarm Manager to start Service at specified time and then repeat alarm in specified interval. When alarm goes on you can start service and connect to server and make what you want
I'm having a problem with my IntentService. Every time I start my service, the onDestroy() method is called as soon as the service becomes idle. I set up my service to run in the foreground, and despite this the service is still being killed right away. I have only one other activity in my application, and it is not calling stopService().
Reading the developer docs gives me the impression that calling startForeground() will allow your service to persist, even when idle, except when there is an very high demand for memory, or am I reading this wrong?
My code below:
public class FileMonitorService extends IntentService {
public int mNotifyId = 273;
public FileMonitorService(){
super("FileMonitorService");
}
#Override
protected void onHandleIntent(Intent arg0) {
}
#Override
public void onDestroy() {
Toast.makeText(this, getText(R.string.toast_service_stop), Toast.LENGTH_SHORT).show();
stopForeground(true);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification(R.drawable.icon, getText(R.string.notification_short), System.currentTimeMillis());
notification.flags|=Notification.FLAG_NO_CLEAR;
Intent notificationIntent = new Intent(this, FileMonitorActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_short),getText(R.string.notification_long), pendingIntent);
startForeground(mNotifyId, notification);
Toast.makeText(this, getText(R.string.toast_service_start), Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent, flags, startId);
}
}
You need to look into using a regular Service instead of an IntentService. IntentService is designed to keep running while it has work to do. Once you've finished your onStartCommand method, it tries to stop.
See the docs:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
(Emphasis mine)