I need to set task on android that will check for new data and download it from the remote server.
Basically i know how to run task, but the question is:
Should i run the scheduleAlarm() method from the main thred?
it means that each time the user opens the app this method is being called.
Would it create duplicated tasks?
What is the proper way to set this kind of task?
public void scheduleAlarm(){
Calendar date = new GregorianCalendar();
date.set(Calendar.HOUR_OF_DAY, 0);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
Intent intentAlarm = new Intent(this, AlarmReciever.class);
// create the object
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//set the alarm for particular time
alarmManager.set(AlarmManager.RTC_WAKEUP,date.getTimeInMillis(), PendingIntent.getBroadcast(this,1, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT));
}
public class AlarmReciever extends BroadcastReceiver{
ConnectivityManager cm = null;
NetworkInfo netInfo = null;
#Override
public void onReceive(Context context, Intent intent)
{
// exec task download data
}
}
Use the PendingIntent to start a service which executes the network request.
PendingIntent.getService(...)
But make sure that it ether an IntentService or the actual network request in executes async.
EDIT: Sorry I misread the question. The last argument in the PendingIntent specifies what to do when the PendingIntent already exists. In the example you are telling that if such an PendingIntent already exists, then it should be updated. So you should be fine as long as the arguments for the PendingIntent stay the same since no new PendingIntent is created.
https://developer.android.com/training/scheduling/alarms.html
according to documentation alarmManager.set will cancel your pending event and schedule new one, which mean onReceive will be called one per event.
If you want to manage task, just keep its intense in AlarmReciever
public class AlarmReciever extends BroadcastReceiver{
ConnectivityManager cm = null;
NetworkInfo netInfo = null;
Task task;
#Override
public void onReceive(Context context, Intent intent)
{
// reschedule alarm
// check if not null and not finished return or cancel old one and create new 'task'
}
}
Related
I have an app that schedules a bunch of notifications (user has to answer questionnaires) locally using AlarmManager. The notification should show at certain points in the future.
I schedule the notifications like this:
private void scheduleNotification(Notification notification, int delay, int scheduleId, int notificationId) {
Intent notificationIntent = new Intent(context, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, notificationId);
notificationIntent.putExtra(NotificationPublisher.INTENT, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, scheduleId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, delay);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
The intent is received by a BroadcastReceiver that calls notify on the notification attached to the intent.
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String INTENT = "notification";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra(INTENT)) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
Notification notification = intent.getParcelableExtra(INTENT);
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
notificationManager.notify(id, notification);
}
}
}
This works fine so far. The problem that I'm facing is that I only want to show the notification if the app is currently not open/shown. If it's open I want to show an AlertDialog instead.
I know that it might be a better idea to put only the plain content of the notification into the intent and only build it when it should be displayed and I want to refactor that later on.
My main problem is, how do I determine in the onReceive of my broadcast receiver if the app is currently showing to decide if a notification or an alert should be displayed?
Or is there an entirely different approach that might work better (for example using WorkManager)?
I think you can handle it on your BroadcastReceiver
public void onReceive(Context context, Intent intent) {
if (isForeground(context))
// AlertDialog
else
// Notification
}
public boolean isForeground(Context mContext) {
ActivityManager activityManager = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).getTaskInfo().topActivity;
return topActivity.getPackageName().equals(mContext.getPackageName());
}
return true;
}
This question already has answers here:
Using Alarmmanager to start a service at specific time
(6 answers)
Closed 6 years ago.
I want to call a function when System timestamp reaches to specific time.
is there anyway better than a CountDownTimer ?
It should be called on a service because i want it still run when app closes.
thanks a lot.
You have to use BroadcastReceiver along with AlarmManager Like this.
//Create alarm manager
AlarmManager malarmMngr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
//Create pending intent & register it to your alarm notifier class
Intent intent = new Intent(this, yourBroadcastReceiver.class);
PendingIntent mPendInt = PendingIntent.getBroadcast(this, 0, intent, 0);
//set your time stamp (for once in future)
malarmMngr .set(AlarmManager.RTC_WAKEUP, yourtimestamp, mPendInt);
Now create yourBroadcastReceiver class to call function.
public class yourBroadcastReceiver extends BroadcastReceiver {
public MyReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
// This method is called when this BroadcastReceiver receives an Intent broadcast.
// Call your function here
}
}
I've a date and time stored in database, I need to continuously monitor the time and date in the background and run a function in the app when that time comes, there can be set of of date and time's, i only know that i need services to do this, but not more than that. can some please tell whether this can be achieved or not? if yes, please suggest me how I can proceed further.Thank u...
Android has a very developer friendly class for that: AlarmManager
So, take the Date an Time from database, define an alarm event with it, subscribe your app for notifications for that and wait until the event comes to do the job you need to do.
this is how:
public class MyAlarm extends IntentService {
private NotificationManager myAlarmNotificationManager;
public MyAlarm() {
super("MyAlarm");
}
//this send the notification
private void sendNotification(String message) {
Log.d("MyAlarm", "Preparing to send notification...: " + message);
myAlarmNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, AlarmActivity.class), 0);
NotificationCompat.Builder alamNotificationBuilder = new NotificationCompat.Builder(
this).setContentTitle("Alarm").setSmallIcon(R.drawable.ic_launcher)
.setStyle(new NotificationCompat.BigTextStyle().bigText(message))
.setContentText(message);
alamNotificationBuilder.setContentIntent(contentIntent);
myAlarmNotificationManager.notify(1, alamNotificationBuilder.build());
Log.d("MyAlarm", "Notification sent.");
}
#Override
public void onHandleIntent(Intent intent) {
sendNotification("Do something");
}
}
I have an Android background service that report positions from time to time. When I test locally over wifi it works pretty well, however when testing in 3G connection for example (sometimes on Edge) I have perceived that the application apparently enters in a bottleneck and do not execute the onLocationChanged method. That's okay because maybe lost signal or so on. However after a while (maybe when connection is re-established) it start updating all requests at once, in a matter of a few seconds many many times the method onLocationChanged is executed.
Does anyone have ideas how to solve that? Is it possible to add timeout into the method locationManager.requestLocationUpdates?
My Listener
public class MyListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
//report location to server
HttlCallToUpdatePostion(loc.Latitude, loc.Longitude, loc.Accuracy);
}
}
My Service
Handler handler = null;
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
MyListener listener = new MyListener();
protected void doWork() {
Looper.prepare();
handler = new Handler();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, listener);
Looper.loop();
}
I wrote an app, exactly what you need.
When it was a service only I met the same problem. While the UI went to background and screen off the service went to background and it scheduled the system calls, once when triggered the buffer was flushed and I had like 10-50 updates.
The solution it is: an Alarm must be set and scheduled with 5000 value and a BroadcastRreceiver will receive and it will handle properly. Than you will meet other problems, which is not asked here.
For me this was a SOLUTION and the app is in use!
Edit:
Alarm setup code part:
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
// In reality, you would want to have a static variable for the request
// code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(this, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
// am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
am.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(), timerInterval, sender);
AndroidManifest.xml :
<receiver android:process=":remote" android:name=".broadcastreceiver.AlarmReceiver"/>
class implementation part:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Context appContext = context.getApplicationContext();
...
check for power saving mode in adorid system setting: it must be disable to permit location manager to generete update location when the screen is off
In my application, I've got an alarm which triggers a service which downloads information from the internet and shows a notification.
Here's a simplified version of my code:
MyActivity contains this:
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 20);
Intent intent = new Intent(this, AlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 20000, pendingIntent);
And AlarmService looks like this:
public class AlarmService extends Service {
#Override
public void onCreate() {
new myAsyncTask().execute();
}
private class myAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... args) {
//Download stuff
return null;
}
#Override
protected void onPostExecute(Void arg) {
//Show notification
}
}
}
I don't really understand when to use wake-locks, so my question: in this case, should I use a wake-lock and if so, where should I start and stop it?
Thanks in advance
Yes, you will need to use a WakeLock to ensure that your service can finish its work.
If using an IntentService meets your design requirements, I would take a look at WakefulIntentService. It manages the alarms and the WakeLocks on your behalf and is easy to set up. The WakeLock is acquired when the alarm fires, and the WakefulIntentService library takes care of releasing it when the service is finished.
If you go this route, you won't want to use AsyncTask -- you'll need to keep the service actively busy (in its doWakefulWork() method) in order to hold the WakeLock.