36958

Android long running service with alarm manager and inner broadcast receiver

I have a Service that uses a custom Connection class (extends thread) to a hardware controller. When the User prefers, I wish to maintain this connection on a permanent basis. I already have the code to handle when the Android device loses its internet connection, switches between wi-fi, etc.

In order to stay connected, the controller requires that you speak to it within every 5 minutes. I currently, within the Connection class start a thread that runs in a while(), and checks the system time and the last time it communicated, and when > 4 minutes it requests a status. For some reason, at different times the communication doesn't occur in time. i.e., occurs after 5 minutes. The Service doesn't die, as far as I can tell but the "Ping" to the controller is late. This doesn't happen when I have the phone plugged into the charger (or debugger). Additionally, the behavior is the same when I move the Service to the foreground.

Does the phone slow down it's processor when it goes to sleep?

Is there a better way?

I'm thinking it's the AlarmManger, but I'm having trouble getting it to work with an inner-class, within the Service. I tried using the API demos as a starting point, but I can't seem to figure out how to get the Broadcast receiver registered. I am trying to register the receiver programmatically, with no changes to the manifest.

public class DeviceConnectionService extends Service { @Override public void onCreate() { Intent intent = new Intent(this, PingConnection.class); intent.setAction("KEEP_CONNECTION_ALIVE"); PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); // We want the alarm to go off 30 seconds from now. long firstTime = SystemClock.elapsedRealtime(); firstTime += 15*1000; // Schedule the alarm! AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, 15*1000, sender); // register to listen to the Alarm Manager if (mPingConnectionReceiver == null) { mPingConnectionReceiver = new PingConnection(); getApplicationContext().registerReceiver(mPingConnectionReceiver, new IntentFilter("KEEP_CONNECTION_ALIVE")); } } // ... public class PingConnection extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (dBug) Log.i("PingConnection", "Pinging Controller"); // do real work here } } }

Answer1:

Does the phone slow down it's processor when it goes to sleep?

The phone shuts down its processor when it goes to sleep. That is the definition of "sleep".

I'm thinking it's the AlarmManger, but I'm having trouble getting it to work with an inner-class, within the Service. I tried using the API demos as a starting point, but I can't seem to figure out how to get the Broadcast receiver registered. I am trying to register the receiver programatically, with no changes to the manifest.

That is an unusual approach for AlarmManager. That being said, since you declined to describe "having trouble" in any detail, it is difficult to help you.

Get rid of getApplicationContext() (you don't need it and really don't want it in this case). I would register the receiver before touching AlarmManager. Before you go to production, please choose an action name that has your package name in it (e.g., com.something.myapp.KEEP_CONNECTION_ALIVE).

Beyond that, check LogCat for warnings.

<hr>

<strong>UPDATE</strong>

In your LogCat, you should have a warning from AlarmManager complaining about not being able to talk to your BroadcastReceiver.

Replace:

Intent intent = new Intent(this, PingConnection.class); intent.setAction("KEEP_CONNECTION_ALIVE");

with:

Intent intent = new Intent("KEEP_CONNECTION_ALIVE");

and you may have better luck.

Answer2:

you can't register AlarmManager in a Service. All you can do is declare it as global in the Manifest.xml. You can start the alarm from service in this way, by declaring it in Manifest.xml

If you have a remote service and you close the launcher activity, the AlarmManager will still run, but don't forget to stop it on onDestroy() method of the service.

I've tried to register only in the Service the AlarmManager as I didn't used it for the main activity, but no success! It didn't work as registering as a normal BroadCastReceiver.

that's how the things are, you have to declare it in Manifest.xml as global

Answer3:

I know it's late, but maybe it's useful for someone else.

You can register it, the problem is when the Intent tries to call it.

Instead of calling it like this:

Intent intent = new Intent(this, PingConnection.class);

Create an empty intent and add an action you are going to listen to:

Intent intent = new Intent(); intent.setAction("value you want to register");

Then create the pending intent and send the broadcast like you have it.

Create an attribute for the receiver so you can access it in the whole class and unregister if necessary (if the pendingIntent is also an attribute you can unregister any time):

private PingConnection pingConnection = new PingConnection();

Register it like this:

IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("the value you used before"); getApplicationContext().registerReceiver(pingConnection, filter);

Now you won't get any errors, and the class is not static, and it's an inner class.

Recommend

  • Ordering list with jQuery drag and drop
  • socket.io with node.js not working as expected
  • PHPUnit picking up on syslog messages?
  • How to wait for a thread to finish execution in C#?
  • SignalR dependency injection via Spring.Net
  • Thread Synchronization with IntentService
  • How to get value of the slider, when touchend or mouseup events are used?
  • Phalcon\\Mvc\\Model::validation() and non-model validators
  • Positioning children objects in scene (car wheels hierarchy)
  • How do I configure Maven Cargo to use an embedded Tomcat server?
  • Deleting a widget from QTableView
  • ASPNetCore MVC Routing Let Server Handle Specific Route
  • Ionic Slide Up Slide Down Animation for only one view in sidebar
  • Is there any purpose for h2-h6 headings in HTML5?
  • ConnectivityManager.CONNECTIVITY_ACTION deprecated
  • How to create CGPath from a SKSpriteNode in SWIFT
  • Simple linked list-C
  • Z3: Convert between FP and BitVector?
  • Using a canvas object in a thread to do simple animations - Java
  • uniform generation of points on 3D box
  • What does 'Language neutral' mean with regard to MAKELANGID?
  • Visual Studio 2010 debugger build correctly - compiler pdb and linker pdb not in synch?
  • WPF - CanExecute dosn't fire when raising Commands from a UserControl
  • iOS: Detect app start via notification press
  • How to attach a node.js readable stream to a Sendgrid email?
  • How to use remove-erase idiom for removing empty vectors in a vector?
  • Highlight one bar in a series in highcharts?
  • formatting the colorbar ticklabels with SymLogNorm normalization in matplotlib
  • Android screen density dpi vs ppi
  • How would I use PHP exceptions to define a redirect?
  • How to extract text from Word files using C#?
  • Hazelcast - OperationTimeoutException
  • Large data - storage and query
  • R: gsub and capture
  • RestKit - RKRequestDelegate does not exist
  • jqPlot EnhancedLegendRenderer plugin does not toggle series for Pie charts
  • Comma separated Values
  • Revoking OAuth Access Token Results in 404 Not Found
  • need help with bizarre java.net.HttpURLConnection behavior
  • How to load view controller without button in storyboard?