I'm trying to get a process timer to run and keep it running in the background on android (starts with a button click).
The timer must be on 30 seconds and should even continue growing application in the background (with home button and power / screen off).
How can I do this? I tried with service and handler but not working ...
EDIT
My service tracking (process with 30 sec)
public class TrackingService extends IntentService {
private Handler mHandler;
private Runnable mRunnable;
public TrackingService() {
super("TrackingService");
}
public TrackingService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
long timer = 30000;
mHandler = new Handler();
mRunnable = new Runnable() {
#Override
public void run() {
//TODO - process with update timer for new 30 sec
mHandler.postDelayed(this, timer);
}
};
mHandler.postDelayed(mRunnable, timer);
}
}
My click button:
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO - start first time and it continued every 30 seconds and continue in the background
startService(Intent intent = new Intent(this, TrackingService.class));
}
});
Ok, first of all, I really don't know if I got your question quite right.
But I think you want a timer that's being executed every 30 seconds ,if i'm not mistaken.
If so, do as following:
AlarmManager
Note: This class provides access to the system alarm services. These allow you to schedule your application to be run at some point in the future. When an alarm goes off, the Intent that had been registered for it is broadcast by the system, automatically starting the target application if it is not already running. Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
Example:
in your onClick() register your timer:
int repeatTime = 30; //Repeat alarm time in seconds
AlarmManager processTimer = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, processTimerReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//Repeat alarm every second
processTimer.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),repeatTime*1000, pendingIntent);
And your processTimerReceiver class:
//This is called every second (depends on repeatTime)
public class processTimerReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//Do something every 30 seconds
}
}
Don't forget to register your receiver in your Manifest.XML
<receiver android:name="processTimer" >
<intent-filter>
<action android:name="processTimerReceiver" >
</action>
</intent-filter>
</receiver>
If you ever want to cancel the alarm:
use this to do so:
//Cancel the alarm
Intent intent = new Intent(this, processTimerReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
Hope this helps you out.
PS: if this is not exactly what u want, please leave it in the comments, or if someone wants to edit this, please do so.
Oh god, don't ever use AlarmManager for 30s timers. It's kind of an overkill and also put a significant drain on device resources (battery, CPU...).
Perhaps you could try using a real background Service instead of IntentService as IntentService tends to shut itself down when it runs out of work. Not sure if this is the case here, but it's worth a try.
Related
I have an android service to fetch data from the web that runs every fifteen minutes
public class SparkService extends Service {
Handler handler;
public SparkService() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("Starting Sevice", "Starting Service Successfully.");
if (handler == null) {
handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
fetchDataFromServer();
handler.removeMessages(120);
handler.sendEmptyMessageDelayed(120, 15 * 60 * 1000);
return true;
}
});
}
handler.sendEmptyMessageDelayed(120, 15 * 60 * 1000);
return Service.START_STICKY;
}
}
I have found the service to be unreliable at times and seems like it's not being called if the app is inactive for a certain period of time. I want to replace the service with an AlarmManager service instead. My app is currently in production. Can I just delete the SparkService class and add another Alarm service class without affecting existing users who update the app? Or would I have to stop this SparkService in my app update so the app can function properly?
Your app is your entry point. So if it's killed that means all services related to its process will also be killed, like if you kill the svchost.exe process in Windows all sub processes like Windows update service will be stopped too and will not be running again until you launch the update manager.
The same goes for your app: the only way that a Service won't be stopped by killing your app (and I'm not sure about that but it can be) is if the Service is created with its own process using a special tag in the Manifest.
I think in your case you didn't set that tag so the Service will be only scheduled once your app is launched after the update and in that case the Service will behave according to the new code.
To answer your first question even if you delete the service from your update users with the old version will not be affected until they update there version with the new one
Now for using Alarm manger to trigger update from your backend as you said it's a good practice as the alarm manager have different set that you can use depending or your need below a short example how to use it
// Get alarm manager instance
AlarmManager alarmManager = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Calendar calendar;
Intent intent;
PendingIntent pendingIntent;
// Schedule
intent = new Intent(getApplicationContext(), YourCustomBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, 0);
calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 1); // first time
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
60*5*1000,//Each five minutes
pendingIntent
);
And in your broadcast receiver
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class YourBroadcastReceiver extends BroadcastReceiver{
publicYourBroadcastReceiver() {}
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context.getApplicationContext(),YourService.class);
context.startService(serviceIntent);
}
}
And here for more details about alarm manager
http://developer.android.com/training/scheduling/alarms.html
According to these examples: here and here, I was trying to create Service which starts periodically.
First I created Service:
public class MonitorService extends IntentService {
private static final String TAG = "MonitorService";
public MonitorService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("TAG", "Service method was fired.");
}
}
Next I created Receiver:
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "MyReceiver on receive");
Intent i = new Intent(context, MonitorService.class);
context.startService(i);
}
}
I added starting method for this in MainActivity:
public void scheduleAlarm() {
Intent intent = new Intent(getApplicationContext(), MyReceiver.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
long firstMillis = System.currentTimeMillis();
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// 1s is only for testing
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis, 1000, pIntent);
}
which is calling of course in onCreate method.
And I didn't forget to change AndroidManifest:
<receiver
android:name=".MyReceiver"
android:process=":remote" >
</receiver>
<service
android:name=".MonitorService"
android:exported="false" />
And unfortunately the result is that nothing happens in my logs.
So I have two questions.
QUESTION
How to solve issue with not starting service?
If I add scheduleAlarm method to onCreate it will be calling every time I start my application, what is the best way to start this method only for the first time application is started?
EDIT
According to #Lasse hints, I started debugging, and realized that Log.d is not working, when I changed it to Log.i, information from MonitorService was logged.
But... debugging is not stoping on breaking point in MyReceiver, and changing Log.d to Log.i there didn't help. Of course MonitorService is firing, weird thing.
Also time with 1000 ms results in firing service every minute, maybe it's minimum time, and changing to AlarmManager.INTERVAL now doesn't matter.
EDIT 2
Finally I'm getting logs from both service and receiver. I had tried many times and after that it is working, but I don't know why.
But with that another problem has appeared - I'm getting warning when my Service is running
W/art: Suspending all threads took: 21.787ms
I thought that Service is running background so it doesn't matter how long it is, should I concern about this warning?
Edited
Regarding the first question :
See this from the developer website
setInexactRepeating(), you have to use one of the AlarmManager interval constants--in this case, AlarmManager.INTERVAL_DAY.
So change your 1000 to use of of the constans
Regarding your other question you could override the application object and start it there. This way it is only called when launching the app.
I have got an intentservice class called by alarmmanager every 5 seconds. Alarmmanager calls intentservice and it works fine. But when it calls, it creates new intentservice. I just want to call intentService's onHandleIntent method not want to create new one. Here is my code:
IntentService class:
public class MyIntentService extends IntentService {
private static final String serviceName = "MyIntentService";
public MyIntentService() {
super(serviceName);
}
public void onCreate() {
super.onCreate();
Log.d("Servis", "onCreate()"); //this is called every 5 seconds too
}
#Override
protected void onHandleIntent(Intent intent) {
//do something
}
}
Setting alarmManager for IntentService
public void setAlarm(View v)
{
Calendar cal = Calendar.getInstance();
AlarmManager am =(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
long interval = 1000 * 5;
Intent serviceIntent = new Intent(context, MyIntentService.class);
PendingIntent servicePendingIntent =
PendingIntent.getService(context, 12345, serviceIntent,PendingIntent.FLAG_CANCEL_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),interval, servicePendingIntent
);
}
I have got an intentservice class called by alarmmanager every 5 seconds.
That will not work on Android 5.1 and higher, where the minimum setRepeating() period is 60 seconds. Also, bear in mind that on Android 6.0+, Doze mode and app standby mode mean that you will not get control anywhere near that often for much of the day.
But when it calls, it creates new intentservice.
That is the point behind IntentService. An IntentService is destroyed once onHandleIntent() ends.
I just want to call intentService's onHandleIntent method not want to create new one.
Then do not use IntentService. Use Service, overriding onStartCommand() instead of onHandleIntent(), and do your own background threading logic. Be sure to stop the service (e.g., stopSelf()) when it is no longer needed.
I am making an application with a feature of alarms in it. I am using service for this which keeps checking the current time of device against the times in my DB.
My problem is that this service stops if the app removed from the background or if the device is rebooted. I have used START_STICKY to keep it running in background and used a broadcast receiver to start it on reboot.
The major concern is that whatever I have coded is working on a MOTO G device. Reboot, clearing from background, everything, the service is running fine. But in Xiomi phones and Huawei Honour, It stops once cleared from background or rebooted.
The Service code:
public class RemindService extends Service {
final long delayMillis=500;
Handler h=null;
Runnable r;
SharedPreferences sp;
PendingIntent pendingIntent;
private static final int NOTIFY_ME_ID=1337;
#Override
public void onCreate() {
h=new Handler(Looper.getMainLooper());
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags,int startId) {
r = new Runnable() {
public void run() {
//SOME OF MY IF-ELSE CONDITIONS
Intent myIntent = new Intent(RemindService.this, ReminderPopUp.class);
int randomPIN = (int)(Math.random()*9000)+1000;
pendingIntent = PendingIntent.getActivity(RemindService.this, randomPIN, myIntent,PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC|AlarmManager.RTC_WAKEUP, System.currentTimeMillis() , pendingIntent);
h.postDelayed(this, delayMillis);
}
};
h.post(r);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
h.removeCallbacks(r);
}
}
My Manifest declarations:
<service
android:name="test.aguai.medieazy.RemindService"
android:enabled="true" />
<intent-filter>
<action android:name="test.aguai.medieazy.START_SERVICE" />
</intent-filter>
Has anybody else faced this problem? I think it is a problem of modified OS, but anyways my app is not working properly. Please Help.
Rather than poll the device database constantly, I would make use of the AlarmManager service as I described in this answer:
Android Polling from a Server periodically
Set up the alarm to fire at the first scheduled time. When it fires, set up the next time and so on. There is no need to set up every alarm at once as only one can ever fire at a time.
When the alarm fires, you can start a service to perform whatever task you need (including the setting of the next alarm)
Try Lik this it will Work
// for Every 6 minutes exact repeating service
Intent myIntent2 = new Intent(sign_in.this,MyAlarmService.class);
pendingintent3 = PendingIntent.getService(sign_in.this, 2,myIntent2, 2);
AlarmManager alarmManager2 = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTimeInMillis(System.currentTimeMillis());
calendar2.add(Calendar.SECOND, 30);
alarmManager2.set(AlarmManager.RTC_WAKEUP,calendar2.getTimeInMillis(), pendingintent3);
alarmManager2.setRepeating(AlarmManager.RTC_WAKEUP,calendar2.getTimeInMillis(), 360 * 1000,pendingintent3);
manifest permission
<!-- Web data Sync Service -->
<service android:name="com.example.MyAlarmService" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</service>
If you want your service to be running until explicitly stopped then consider calling startService(), to start the service. This allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService().
Remember you must explicitly stop the service, by calling stopSelf() or stopService().
I've this IntentService:
public class ServiceUpdateNewResults extends IntentService{
private void setAlarmToCheckUpdates() {
Calendar calendar = Calendar.getInstance();
//calendar.add(Calendar.DAY_OF_YEAR, 1); //dema
//calendar.set(Calendar.HOUR_OF_DAY, 22); //a les 10
calendar.add(Calendar.SECOND, 20);
Intent myIntent = new Intent(this.getApplicationContext(), ReceiverCheckUpdates.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, myIntent,0);
AlarmManager alarmManager = (AlarmManager)this.getApplicationContext().getSystemService(this.getApplicationContext().ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
}
public ServiceUpdateNewResults() {
super("ServiceUpdateNewResults");
}
#Override
protected void onHandleIntent(Intent intent) {
//fem les coses.
//Toast.makeText(this.getApplicationContext(), "holaa", Toast.LENGTH_LONG).show();
setAlarmToCheckUpdates();
Log.d("debugging","hello");
}
}
And this is calling a BroadCastReceiver every 20 seconds, which ends up calling this service, and this is going to happen "forever". (in a future it will be 1 day, not 20 seconds).
This is the Receiver:
public class ReceiverCheckUpdates extends BroadcastReceiver{
Context context;
#Override
public void onReceive(Context context, Intent intent){
this.context = context;
Intent service1 = new Intent(context, ServiceUpdateNewResults.class);
context.startService(service1);
}
}
This is working perfectly, but if I stop the app from Android settings, the service is also stopped. I want to avoid this. I want that if the App is closed, the service should keep working.
Is it possible?
Actually, when is a service killed ?
if I stop the app from Android settings, the service is also stopped
If by "stop the app from Android settings", you mean that you press the Force Stop button, your app will not run again until something manually runs one of your components (e.g., user launches your activity). More specifically in this case, your alarms are unscheduled.
I want to avoid this.
Then do not press the "Force Stop" button.
I want that if the App is closed, the service should keep working.
In any non-"Force Stop" scenario, the alarms will keep firing (at least until the device falls asleep, given your current implementation).
The IntentService is part of your app. If the system destroys your app, it will destroy the IntentService. You can reduce the chances of this happening by putting the IntentService in a separate process, but you can't stop the system from destroying an IntentService. You can make it highly unlikely that the system will destroy a Service; to do that, you use a "foreground" Service. However, you should avoid doing this unless you really really need to. In addition, you can't have a foreground IntentService, so you'll have to add your own background Handler and HandlerThread.