Android: Using wakelock in service triggered by alarmmanager - java

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.

Related

How to set task on android that will run each midnight?

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'
}
}

IntentService not working

I am building an application whereby the notification will ring at a specific time and after which disappear if it is left unattended for 15 minutes. It works when i plug in my device and runs the code. However, once i unplug my device and runs the app, the notification works but it does not disappear after 15 minutes if it is left unattended. Please advice me how should i run the app like how it does when the device is plug into the computer. Also, it should work when the app is killed.
FYI, i'm using notification, alarmmanager, broadcast receiver and intentservice. Below is the snippet of my codes.
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Notification(context, "Wifi Connection On");
Intent background = new Intent(context, BackgroundService.class);
context.startService(background);
}
public void Notification(final Context context, String message) {
// notification codes
}
}
BackgroundService.java
public class BackgroundService extends IntentService {
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
//countdown 15 minutes and cancel notification automatically
Timer timer=new Timer();
TimerTask task=new TimerTask() {
#Override
public void run() {
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Dismiss Notification
notificationmanager.cancelAll();
}
};
timer.schedule(task, 900000);
}
}
Manifest.xml
<receiver android:name=".AlarmReceiver" android:process=":remote" />
<service android:name=".BackgroundService" />
Please provide me some suggestions. Thank you.
This service will run twice: first time it does nothing except rescheduling, second time it cancels notifications.
public class BackgroundService extends IntentService {
private static final int REQUEST_CODE = 42;
private static final String ACTION_CANCEL_NOTIFS = "CancelNotifications";
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null && ACTION_CANCEL_NOTIFS.equals(intent.getAction())) {
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationmanager.cancelAll();
}
else {
reschedule();
}
}
private void reschedule() {
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MINUTE, 15);
final Intent serviceIntent = new Intent(this, getClass());
serviceIntent.setAction(ACTION_CANCEL_NOTIFS);
PendingIntent pendingIntent = PendingIntent.getService(this, REQUEST_CODE, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
Explanation:
In your code, I assume, you start your service with startService(new Intent(this, BackgroundService.class)). This intent is passed as a parameter in onHandleIntent(Intent), which means you can access it from inside your service.
Intent allows you to pass additional data, such as action (useful for IntentFilters) or extras. Because you haven't set any, the first time around the execution goes to the else branch of onHandleIntent() method. AlarmManager is then scheduled to run your service in 15 minutes with serviceIntent. Note serviceIntent.setAction(ACTION_CANCEL_NOTIFS). So the second time around the execution goes to the if branch and cancels notifications.
A better approach would be creating a pending intent right from inside your activity instead of starting a service with startService. That would make your service simpler and more cohesive.
Service only runs when CPU is awake. If CPU gets off, service will not run.
SO to make your service to be run if phone goes to sleep, you need to aquire wake lock.
BackgroundService class
public class BackgroundService extends IntentService {
private PowerManager.WakeLock wl;
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Partial lock permission");
wl.acquire();
//countdown 15 minutes and cancel notification automatically
Timer timer=new Timer();
TimerTask task=new TimerTask() {
#Override
public void run() {
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Dismiss Notification
notificationmanager.cancelAll();
wl.release();
}
};
timer.schedule(task, 900000);
}
}
If this does work out, try to give below permission in Android Manifest file
<uses-permission android:name="android.permission.WAKE_LOCK" />

android stopwatch/timer app - switching back to app when time runs out

I'm developing an app, as mentioned in title. I need somehow to manage that application will be running/counting time even when user starts/switches to another application. Well, as I learned from another discussion at stackoverflow.com, there is no need to create service that works in background and pointlessly burden processor with counting time when app is not active.
Everything what is needed to be done is to store current time when user switch to another app, compare it to time when he switches back and update the UI according to difference between these times. That's for stopwatch mode. When in timer mode, I need to automatically switch back to application according to time, that is app's UI showing when going o background. What could be the best solution suitable for this and can you give me please some simple examples for this?
Use AlarmManager for that. AlarmManager allows you to schedule tasks and get notified when they are fired.
So use AlarmManager
public class MainActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//call function where you want
timeout();
}
public void timeout()
{ //time in milliseconds 1 minute
Long time = new GregorianCalendar().getTimeInMillis()+60*1000; //i.e.60*1000=1minute
// create an Intent and set the class which will execute when Alarm triggers, here we have
Intent intentAlarm = new Intent(this, AlarmReciever.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,time, PendingIntent.getBroadcast(this,1, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT));
}
}
Here is broadcast class:
public class AlarmReciever extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
// show dialog or what you want
}
}
Don't forgot to edit AndroidMainfest:
//permission
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
//our receiver
<receiver android:name=".AlarmReciever"/>

How to call my Android PollingService?

I'm trying to make my android app poll the server for new messages using the example code in this blogpost. I managed to copy paste everything in my project. When I run my project however, it doesn't seem to do anything.
So I've got a PollingService class in a separate file (full code here) in which I tested whether it even gets called using the following constructor:
public class PollingService extends Service {
public void PollingService() {
Log.wtf("I AM ACTUALLY RUNNING", "IN THE Constructor!!!!");
}
I try to call the PollingService using the following onResume from within my mainActivity:
public void onResume() {
super.onResume();
int seconds = 3;
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, PollingService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
alarmManager.cancel(pendingIntent);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + seconds*1000, seconds*1000, pendingIntent);
}
Does anybody know why the PollingService doesn't run? All tips are welcome!
As I see from the code posted, the service is declaring a void method, not a constructor and that's probably the reason why you won't see the log.
Try:
public class PollingService extends Service {
public PollingService() {
super("PollingService");
Log.v("PollingService", "constructor");
}
...
}

Android - Location Manager requestLocationUpdates bottleneck

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

Categories

Resources