Only one instance of an IntentService - android

I would like to setup an IntentService to fire on a timer and manually. In the case that new data is created I would like to 'manually' trigger the IntentService to send the data off immediately. The timer will just run every few minutes to ensure all data has been sent off, if it has not it will send data.
Is there a way to block/lock the IntentService such that if I am already sending data manually and the timer fires the service does not try and submit the same data twice?
I have the following IntentService which will pull an item out of the database and post that info to a server.
public class MyIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
Long id = intent.getLongExtra(SERVICE_ID, -1);
// grab stuff out of DB based on id and submit to server
}
}
I have a BroadcastReceiver that fires every so often to start that intent service:
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
//Grab stuff I care about
Long someId = ....;
Intent i = new Intent(context, MyIntentService.class);
i.putExtra(SERVICE_ID, someId);
context.startService(i);
}
}
And I start the broadcast receiver, to fire every 10 minutes
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
intent = new Intent(getApplicationContext(), MyBroadcastReceiver.class);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1001, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 60 * 10, pendingIntent);
I fire manually elsewhere in code based on an event when I have new data to send
// On some event happened manually start intent (not on timer)
Context context = getApplicationContext();
Intent intent = new Intent(context, MyIntentService.class);
intent.putExtra(SERVICE_ID, someId);
context.startService(intent);
Again can I block somehow to ensure there are not multiple MyIntentServices running at the same time, which could be possibly sending the same data?

Related

How to change the url of WebView and timed refresh the page by connecting to the back-end server

I want to achieve this function:
There is a background service:
1) When the network is off-line, the background services continue to detect, if the resumption of the network, refresh webView, restore display.
2) When the network is OK, the background services will continue to detect, if the background server is given a new url, then refresh the current page.
You can make use of a Broadcast Receiver along with AlarmManager and PendingIntent. Set repeating of the Alarm for your desired duration, and fire the pending Intent at that duration.
public void scheduleAlarmForURLAutoUpdate() {
Long time = new GregorianCalendar().getTimeInMillis()+1000 * 60 * 60 * 24;// current time + 24 Hrs
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent intentAlarm = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, time, 1000 * 60 * 60 * 24, intentAlarm);// 24 Hrs
//Toast.makeText(this, "Alarm Scheduled for 24 Hrs", Toast.LENGTH_LONG).show();
}
AlarmReceiver Class
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
updateURL(context);//Method to update the URL from the server and then refresh your WebView activity
}
public class AlarmReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Intent i = new Intent(context, AutoUpdateService.class);
context.startService(i);
}
}

Call web service in interval on background

Application need synchronize data from server in interval (for example every 30min) or manually on background. Result is saved to local database. After sync is done I want remind activity/fragment ... and force update list (if needed). There are many activities, so I want move it outside of activity and make it more consistent.
For now I created AsyncTask which get result from server and save to DB.
What shoud I use? BroadcastReciever, Service, AlarmManager?
UPDATE
Based on answers I start alarm in Application
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
manager.setInexactRepeating(AlarmManager.RTC, 0, AlarmManager.INTERVAL_HALF_HOUR, pendingIntent);
Created Receiver
public class AlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent syncIntent = new Intent();
syncIntent.setClass(context, DataSyncer.class);
startWakefulService(context, syncIntent);
}
}
Created IntentService
public class DataSyncer extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
// get data from server
// save to DB
AlarmReceiver.completeWakefulIntent(intent);
}
}
And registered Receiver and Service in AndroidManifest
<service
android:name="com.cloudit.tsystems.app.DataSyncer"
android:enabled="true">
</service>
<receiver
android:name="com.cloudit.tsystems.app.AlarmReceiver"
android:enabled="true">
</receiver>
Where and how I notify that sync is done in Activity/Fragment?
I would use the AlarmManager and register a BroadcastReceiver. Once the receiver is fired, I will launch an IntentService to download the data in the background.
Configure your alarm:
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyBroadcast.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
manager.setInexactRepeating(AlarmManager.RTC, 0, AlarmManager.INTERVAL_HALF_HOUR, pendingIntent);
Create a BroadcastReceiver that will get notified when the alarm goes off. Note that I'm using a WakefulBroadcastReceiver so that the device doesn't go to sleep when you're syncing.
class MyBroadcast extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent syncIntent = new Intent();
syncIntent.setClass(context, DataSyncer.class);
startWakefulService(context, syncIntent);
}
}
Next, an IntentService that will download data in the background:
class DataSyncer extends IntentService{
...
#Override
protected void onHandleIntent(Intent intent) {
//sync data
MyBroadcast.completeWakefulIntent(intent);
}
}
Update:
So now that you have your data synced, there are several options to notify Activities and Fragments. You can use a LocalBroadcastManager to broadcast. Take a look at this link for more details.
Use an AlarmManager to trigger a PendingIntent on a 30 minute interval that starts an IntentService to do your download.
Intent intent = new Intent(context, PollingService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(
AlarmManager.RTC,
System.currentTimeMillis(),
AlarmManager.INTERVAL_HALF_HOUR,
pendingIntent
);
When the IntentService is done updating your data, it can send a Broadcast that your Activity/Fragment has registered to listen for to notify it of new data and refresh it's view.
sendBroadcast(new Intent("DATA_UPDATED"));
In your Fragment
getActivity().registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//update UI
}
}, new IntentFilter("DATA_UPDATED"));

How to pass data from Service to Broadcastreceiver

I am calling broadcast receiver from service through this method.
Intent intent = new Intent(NotifyService.this, AlarmReciever.class);
intent.putExtra("TIME",ttime);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 34324243, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,timee,pendingIntent);
In Broadcastreceiver page I am receiveing through this method.
Bundle b = in.getExtras();
date = b.getString("TIME");
Problem is In Broadcastreceiver page I am getting null value.
My Question is :-
How to pass data from service to broadcastreceiver ?
In your main activity start your service as
i = new Intent(this, SimpleService.class);
startService(i);
registerReceiver(broadcastReceiver, new IntentFilter(SimpleService.BROADCAST_ACTION));
use send broadcast to send any value from service class to mainactiviy class as
intent.putExtra("textval", s);
sendBroadcast(intent);
and then in your main activity class receive it as
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//do your coding here using intent
}
};
OK i assume the "ttime" is a bundle ( from the code your wrote it seems to make sense)
Try and recieve the data like this
Bundle b= in.getBundleExtra("TIME");
In case the "tttime" is of other format say a String or Int you can get the data in onReceive of Broadcastreceiverlike this
String :
in.getStringExtra("TIME");
Integer :
in.getIntExtra("TIME", -1) // -1 is default value which will be return incase no matching integer found with the key "TIME" in intent "in"
For full details and how to get data from intent of different type refer to android documentation
you missed to do like this:-
Intent intent = new Intent(NotifyService.this, AlarmReciever.class);
sendBroadcast(intent);
You can call pendingIntent Like this:-
PendingIntent operation = PendingIntent.getBroadcast(Service.this,
0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(),5* 60 * 1000, operation);
If you are passing any time data to broadcast class,then you can receive that data in receiver class as
String mTime = NotifyService.time;
Try this. Inform me also.

Modifying Alarms Which Trigger Services Based on Screen Status

I am currently starting a service using a Broadcast Receiver which fires 60 seconds after the device boots up. This broadcast receiver triggers an alarm so that my service runs every 60 seconds. Code for this is as follows:
public class ScheduleReceiver extends BroadcastReceiver {
// Restart service every 60 seconds
private static final long REPEAT_TIME = 1000 * 60;
#Override
public void onReceive(Context context, Intent intent) {
AlarmManager service = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, StartServiceReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, i,PendingIntent.FLAG_CANCEL_CURRENT);
Calendar cal = Calendar.getInstance();
// Start 60 seconds after boot completed
cal.add(Calendar.SECOND, 60);
// Fetch every 60 seconds
// InexactRepeating allows Android to optimize the energy consumption
service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), REPEAT_TIME, pending);
}
}
The above starts the service as follows:
public class StartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, PhotoService.class);
context.startService(service);
}
}
I would like to somehow modify this so that my service runs every 60 seconds when the phone screen is on and every 20 minutes when off.
What is the best way to do this ? Can I modify the alarm dynamically when the screen is switched off/on ?
Thanks for any help,
Regards,
Fido
Okay I have found out how to do this so I thought I would put this here in case anyone else is ever curious. (More elegant solutions are always welcome):
First thing is that in my service I added the following to the OnCreate:
#Override
public void onCreate() {
super.onCreate();
// REGISTER RECEIVER THAT HANDLES SCREEN ON AND SCREEN OFF LOGIC
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScheduleReceiver();
registerReceiver(mReceiver, filter);
}
This is done so that my broadcast receiver can handle those events. Apparently you cannot register these via intent-filters in the xml.
This means that when the service is created it ensures that these additional system actions can be handled.
I then modified my broadcast receiver to be:
public class ScheduleReceiver extends BroadcastReceiver {
private static final int ALARM_ID = 909;
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
AlarmManager service = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, StartServiceReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(context, ALARM_ID, i,PendingIntent.FLAG_CANCEL_CURRENT);
service.cancel(pending);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 60); //Delay startup by one minute - This is useful to prevent over utilization of resources at boot
// Start alarm. Set a long repeat time if the screen is off and a short repeat time if the screen is on
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON) || intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 60000, pending);
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 600000, pending);
}
}
}
From the above I cancel any current alarms with the same pending intent and then I set a new alarm whenever the screen if switched off/on.
This seems to be working for me. As always any improvements are very welcome.

Android Pending intent?

I have pending intent that sets alarm and it takes parameters such as row id and time from a database. I want to cancel alarm so i would do that by sending another pending intent with the same info and then cancel(i want to cancel it from different file). I only allow one alarm to be set at anyone time because that's the way my app works, because there is only one alarm set from that pending intent is there anyway i can just do cancel all for that intent?
Since I believe in code samples to get the point across, see below:
/*
* An alarm can invoke a broadcast request
* starting at a specified time and at
* regular intervals.
*/
public void sendRepeatingAlarm()
{
Calendar cal = Utils.getTimeAfterInSecs(30);
String s = Utils.getDateTimeString(cal);
this.mReportTo.reportBack(tag, "Schdeduling Repeating alarm in 5 sec interval starting at: " + s);
//Get an intent to invoke TestReceiver class
Intent intent = new Intent(this, TestReceiver.class);
intent.putExtra("message", "Repeating Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 2);
// Schedule the alarm!
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
5*1000, //5 secs
pi);
}
protected PendingIntent getDistinctPendingIntent(Intent intent, int requestId)
{
PendingIntent pi =
PendingIntent.getBroadcast(
this, //context
requestId, //request id
intent, //intent to be delivered
0);
//pending intent flags
//PendingIntent.FLAG_ONE_SHOT);
return pi;
}
/*
* An alarm can be stopped by canceling the intent.
* You will need to have a copy of the intent
* to cancel it.
*
* The intent needs to have the same signature
* and request id.
*/
public void cancelRepeatingAlarm()
{
//Get an intent to invoke TestReceiver class
Intent intent = new Intent(this, TestReceiver.class);
//To cancel, extra is not necessary to be filled in
//intent.putExtra("message", "Repeating Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 2);
// Schedule the alarm!
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi);
}
I have pending intent that sets alarm and it takes parameters such as row id and time from a database.
There are no "parameters" on a PendingIntent. I am going to interpret this as meaning "extras".
I want to cancel alarm so i would do that by sending another pending intent with the same info and then cancel(i want to cancel it from different file).
It's not "sending" but "creating". Otherwise, yes, this is correct.
i can just do cancel all for that intent?
There is only one alarm.
Extras do not matter in terms of alarm scheduling. If you have an Intent (I1) wrapped in a PendingIntent (PI1) and use that to schedule an alarm, and later if you create an Intent (I2) with the same component/action/data/type, wrap that in a PendingIntent (PI2) and cancel() the alarm, it will cancel the PI1 alarm. Similarly, if you use PI2 to schedule a new alarm, it will remove the old PI1 alarm.

Categories

Resources