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.
Related
I need to periodically read data from Google Fit via the Fitness API for a watch face development.
I'm using AlarmManager every POLL_INTERVAL_MS interval to broadcast an Intent to a WakefulBroadcastReceiver which starts an IntentService executing the data read task.
This is the code I'm using.
In the manifest file
<receiver android:name=".FitDataAlarmReceiver"></receiver>
In watch face engine onCreate
FitDataAlarmReceiver mFitDataAlarmReceiver = new FitDataAlarmReceiver();
mFitDataAlarmReceiver.setAlarm(MyApp.this);
In FitDataAlarmReceiver class
public class FitDataAlarmReceiver extends WakefulBroadcastReceiver {
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
private static final long FIT_DATA_POLL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(60);
public void setAlarm(Context context) {
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, FitDataAlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 123456, intent, 0);
alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, POLL_INTERVAL_MS, POLL_INTERVAL_MS, alarmIntent);
}
public void cancelAlarm(Context context) {
if (alarmMgr!= null) {
alarmMgr.cancel(alarmIntent);
}
}
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, FitDataManagerService.class);
startWakefulService(context, service);
}
}
In my IntentService I then obtain a new wake lock, start the data read stuff and then release it together with the receiver one (by calling completeWakefulIntent method).
cancelAlarm method is of course called in the watch face onDestroy.
mFitDataAlarmReceiver.cancelAlarm(MyApp.this);
It works. But, what's happening is that the onReceive in the FitDataAlarmReceiver class is triggered twice very quickly without even respecting the first POLL_INTERVAL_MS parameter of the setRepeating method call.
It takes a couple of - literally - false alarms before the receiver starts receiving correctly timed invocations. I don't know why.
SetAlarm is called only once in the onCreate method of the watch face engine.
However the onCreate method of the watch face engine itself is also (inexplicably) being called two times(!).
I've filtered out the second onCreate call by using a simple semaphore, and it is now called only once.
Nevertheless, onReceive is still called twice.
Only if I use the debugger and place a breakpoint in the onReceive, it is called just once.
These are my questions:
Why is the onCreate method in the watch face Engine class called two times?
And, even if I manage to filter out one call, why is the receiver onReceive being called twice?
I want to make an app in which my audio profile mode change according to location. For this purpose I always need to check location in background. How can I do this in background? Where to right my actual location getting and comparison code in Service class and when to start my service class?
Below is an example of IntentService that restarts itself every 5 minutes.
public class MyIntentService extends IntentService {
int updateVal;
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
// your code here. Request location updates here.
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
//minutes after which the service should restart
updateVal = 5;
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
//This is to incorporate Doze Mode compatibility on Android M and above.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
alarm.setAndAllowWhileIdle(
alarm.RTC_WAKEUP,
System.currentTimeMillis() + (1000 * 60 * updateVal),
PendingIntent.getService(this, 0, new Intent(this, MyIntentService.class), 0)
);
//For all other versions.
else
alarm.set(
alarm.RTC_WAKEUP,
System.currentTimeMillis() + (1000 * 60 * updateVal),
PendingIntent.getService(this, 0, new Intent(this, MyIntentService.class), 0)
);
}
}
In your main activity, type this code to start the service.
startService(new Intent(this, MyIntentService.class));
You have to implement LocationListener and get the location updates which I haven't added into the code.
If you really wish to start a service that never stops, you need to extend Service class instead of IntentService class. It has been very well explained in the Android Developers guide: http://developer.android.com/guide/components/services.html
Use service that return "START_STICKY" in onStartCommand() function. Your service will be restarted again after it was killed by system. However sometimes , it will not be restarted. To make your service 100% alive, use foreground service. Anyway foreground service requires a notification that always shown.
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.
At point A in my application I start my service and expect the service get closed from point B. However, there might be few scenarios that point B doesn't ask service to get closed. In this case I want the service close itself after fixed amount of time.
I have written following code into my Service class and expect the service gets closed after 10 seconds from launch time (It will be 45min in the future but I don't want to stay that long for test).
public class ChatService extends Service implements ITCPConnection
{
private static final int SERVICE_LIFE_TIME = 10 * 1000; // In millis
private AlarmReceiver mAlarmReceiver;
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
#Override
public void onCreate()
{
super.onCreate();
//
mAlarmReceiver = new AlarmReceiver();
registerReceiver(mAlarmReceiver, new IntentFilter());
//
Intent intent = new Intent(this, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + SERVICE_LIFE_TIME, alarmIntent);
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.e(TAG, "onDestroy()");
// Unregister receiver
if (mAlarmReceiver != null)
{
unregisterReceiver(mAlarmReceiver);
}
disconnect();
}
public void disconnect()
{
// If the alarm has been set, cancel it.
if (alarmMgr!= null)
{
alarmMgr.cancel(alarmIntent);
}
...
Log.e(TAG, "disconnect()");
}
/*****************
* Alarm Receiver
*****************/
private static class AlarmReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.e(TAG, "Stop service from AlarmReceiver");
context.stopService(intent);
}
}
}
My problem is AlarmReceiver.onReceive() never gets called and therefore my service will be alive indefinitely.
What you are trying to do is to targeting a broadcast receiver explicitly.
According to this, it cannot be done over a dinamically created (i.e. not declared into the manifest) broadcast receiver, because the os would not know how to resolve it.
To check if this is the root of the problem, you can go with the implicit way and set an action inside the intent and by filtering it in the IntentFilter.
Anyway, using the post delayed can be seen as a valid alternative, since you expect the service to be shut down naturally or still be around to intercept the delayed event.
Another (unrelated) thing is that you are calling
context.stopService(intent);
by using the broadcast intent and not the intent that started the service. You could simply call stopSelf().
I'm trying to make a Service, wake up and call itself again after one minute (in this example, I know its bad for battery).
Here is part of the code:
public class SpeechService extends Service {
#Override
public void onCreate() {
super.onCreate();
setUpNextAlarm();
}
public void setUpNextAlarm(){
Intent intent = new Intent(SpeechService.this, this.getClass());
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
long currentTimeMillis = System.currentTimeMillis();
long nextUpdateTimeMillis = currentTimeMillis + 1 * DateUtils.MINUTE_IN_MILLIS;
// Schedule the alarm!
AlarmManager am = (AlarmManager)ContextManager.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,nextUpdateTimeMillis, pendingIntent);
Log.e("test","I am back!");
}
protected void onHandleIntent(Intent intent)
{
Log.e("test","I am back!");
setUpNextAlarm();
}
}
As you can see I'm calling setUpNextAlarm on service create, I see the log at the end, but then the service is never being called again. I have tried this in an IndentService, it works but I need it to work in a normal Service :(.
Thank you
Use
PendingIntent.getService
not
PendingIntent.getBroadcast
You are getting a Broadcast Intent.
I just ended up using a Service and an IntentService. The IntentService was using the AlarmManager and then it was calling the Service.