Implementing an android service for polling at regular intervals - android

What is the best way to implement an android Service (not IntentService) which polls a device using SNMP at regular intervals? I've tried implementing it with a Handler.postDelayed(Runnable) within onHandleIntent of IntentService. But later found it cannot be used in onHandleIntent() from this answer. My code just would not execute the runnable part.
make an IntentService not sleep until it executes a handler.postDelayed runnable
My code goes like:
public class MyPoller extends IntentService {
//Variable declarations
protected Handler handler;
public MyPoller() {
super("My service");
}
#Override
protected void onHandleIntent(Intent intent) {
.......
.......
runable = new Runnable() {
public void run() {
//My code here
handler.postDelayed(this, poll_interval);
}
};
handler.postDelayed(runable,poll_interval);
}
}
So I thought I could implement the same in a service, but I don't know how to implement this recurring task in a service also running it in a new thread. I found few answers demonstrating different ways of running recurring tasks in a new thread in a Service, but I'm confused.
Can someone suggest some way of implementing the same in a Service? It would be of great help. Thanks in advance.

Related

Checking for new data in background

What is the recommended approach for checking for new data regardless if the app is in the foreground or background? I am wondering which Android API people are typically using to do this. There seems to be a few ways to achieve my goal, and I want to make sure I'm on the right path.
I have something put together which uses AlarmManager.SetInexactRepeating() to call an IntentService which does the sync and inserts/updates data in the database. This works while the app is in the foreground and background, but if I force stop the app then I keep seeing "Unfortunately, has stopped working" messages when the AlarmManager alarm would've triggered. In this case, I only care about checking for new data only when the app is running in the foreground or background.
My first thought is to detect when the app is force closed, and stop the alarm, but that does not seem possible. So I am asking here, is my approach wrong? If so, which approach is used to perform some periodic task regardless if the phone is in the foreground or background? The problem with the AlarmManager solution I am using is the alarms continue to fire even when the app is closed.
If your idea is to check if your API has new data and perform a background sync to your local database or other data storage, I think you would like to take a look at this:
Creating a Sync Adapter
Running a Sync Adapter
The Sync adapter is the recommended way of achieving this in Android. The pros of using it are multiple:
Optimisations out of the box - the OS bundles calls, uses the most appropriate windows to run the sync adapter at a minimal bandwidth and battery cost
The lifecycle of your background sync component is managed internally by the OS
Observers can be notified when data has been changed so the UI can be updated easily
Multiple ways of running the sync - at intervals, automatically with the OS message to keep TCP/IP connections open or on demand
However, implementing this requires some things, that can cause a bit of a pain at first:
It is mandatory that the adapter works with a ContentProvider
Sync Adapters use Account for authentication. If this is not needed, a Stub has to be provided
For backgrounding on Android usually you use even a Service that can run alone and independently from the App or a Bounded service that takes and returns data from the App. A complete reference on backgrounding can be found here
Using a Service is the right way to go. Have your app start the Service and it will continue running while the app is in the foreground or the background. Then, if you want to kill the Service when your app closes, you could just call stopService(yourServiceIntent); from the onDestroy() override in your app's activity. That should effectively shut down the service when the app closes.
So some sample code of how this works (taken from the Services docs)...
The Service (just Logs a message every 1 second for 60 seconds):
public class MyService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
long endTime = System.currentTimeMillis() + 60*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(1000);
Log.d("SERVICE", "The service is still running.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
}
}
And in your activity you would do something like:
public class MainActivity extends AppCompatActivity {
Intent serviceIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);
}
#Override
protected void onDestroy() {
stopService(serviceIntent);
super.onDestroy();
}

Make Asynchronous Calls to a Service (Android)

Right now I have an Activity and a local Service. I need to be able to call a service method asynchronously from the activity. The only ways I know of communicating between a service and an activity is through Intents, binding, and AIDL.
I tried binding, but bound service calls are synchronous.
Using intents (modifying the intent passed to startService) doesn't work either because onStartCommand is called on the main thread.
I'd rather not resort to AIDL because it seems rather complicated. Any alternatives I'm missing?
btw Making Asynchronous Service calls in Android does not answer my question
PROLOGUE
Following CommonWare's answer I decided to use a service with a ThreadPoolExecuter
The only ways I know of communicating between a service and an activity is through Intents, binding, and AIDL.
AIDL is binding. AIDL makes it possible to bind between apps.
I tried binding, but bound service calls are synchronous.
Make the call in a background thread, then.
Using intents (modifying the intent passed to startService) doesn't work either because onStartCommand is called on the main thread.
The service can use a background thread, then. For example, an IntentService supplies a background thread, passing the Intent delivered originally to onStartCommand() on to your onHandleIntent() method.
Any alternatives I'm missing?
None that avoid the background thread.
Turns out, an IntentService did not work for me because I needed persistent objects and IntentServices close after all jobs are finished. Instead, I used a service with an Executor, which I made to run all my service requests on a single background thread.
handleMessageHelper handles all requests on a background thread. I use a Messenger to recieve requests, and use a custom Runnable to pass the msg to my handleMessageHelper method
MyService.java (snippet)
ExecutorService background = Executors.newSingleThreadExecutor();
//handles messages from client
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
background.execute(new MessengerRunnable(msg));
super.handleMessage(msg);
}
class MessengerRunnable implements Runnable {
public Message msg;
public MessengerRunnable(Message m) {
super();
msg = m;
}
#Override
public void run() {
handleMessageHelper(msg);
}
}
}
//called from handleMessage in IncomingHandler
//should be run on `background` ExecutorService
public void handleMessageHelper(Message msg) {
Log.d("CASE: ","" + msg.what);
switch (msg.what) {
case SET_ACCOUNT:
Bundle b = msg.getData();
String accountName = b.getString("accountName");
if (accountName != null) {
setAccount(accountName);
}
break;
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());

make an IntentService not sleep until it executes a handler.postDelayed runnable

In the onHandleIntent of my my IntentService class, I created handle containing a runnable which should be done after 20 seconds. Unfortunatly my service sleeps or is destroyed before this period.
I tried also with the CountDownTimer, but i had the same problem.
Do someone have any idea can I make the onHnadleIntent waiting? Thank you!
This is the code:
public class MyService extends IntentService {
//...
#Override
protected void onHandleIntent(Intent workIntent) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.i("20 seconds later","I am here");
}
}, 20000);
//...
}
//...
}
Don't use an IntentService. It is not designed for your scenario. Use a regular Service. Put your code in onStartCommand(). At the bottom of your run() method, call stopSelf() on the Service instance to shut it down.
You need to stop onHandleIntent from returning until the Runnable has completed. This can be achieved by using a CountdownLatch, which awaits at the end of your onHandleIntent method, and gets released at the end of the run method.
NOTE: this will cause the intent service to not process other Intents you sent it until the previous one has completed (after 20 seconds).
You may also want to obtain a partial wakelock at the start of onHandleIntent and release it at the end.

IntentService and Threadpool

i have an IntentService that should act like a manager and create Tasks in a queue (Runnable) that are submitted to a ThreadPool.
Im a little bit confused of the lifecycle of an IntentService:
The method protected abstract void onHandleIntent (Intent intent) runs already on a separated Thread. In the onHandleIntent I would create a new Runnable instance and submit it to the ThreadPool. My Service looks like this:
public class SyncService extends IntentService {
private final ThreadPoolExecutor threadPool;
public SyncService() {
super("SyncService");
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
threadPool = new ThreadPoolExecutor(1, 1, 20, TimeUnit.SECONDS, queue);
}
#Override
public void onCreate() {
super.onCreate();
EventBus.getInstance().register(this);
}
#Override
public void onDestroy() {
super.onDestroy();
EventBus.getInstance().unregister(this);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent.getAction().equals("sync")){
threadPool.submit(new SyncRunnable());
}else
if(intent.getAction().equals("delete")){
threadPool.submit(new DeleteRunnable());
} else
if(intent.getAction().equals("register")){
threadPool.submit(new RegisterRunnable())
}
}
}
My questions:
Is it a good idea to use a ThreadPool in a IntentService?
If I use a ThreadPool, than the IntentService will be destroyed if the Threadpool has no more Runnables to execute or queued, right?
Is IntentService already something that I want to achieve and should I simply execute my (long running) Runnable code in the
onHandleIntent() because this method alread runs on the
IntentService worker Thread? If yes, is there a queue limit for
intent, since onHandleIntent() could run up to 30 seconds before
finishing and handling the next Intent.
Is it a good idea to use a ThreadPool in a IntentService?
Not really. IntentService is already a single threaded (serial) variant of what you try to achieve. I would derive directly from Service.
If I use a ThreadPool, than the IntentService will be destroyed if the Threadpool has no more Runnables to execute or queued, right?
No. IntentService can go into the destroyed state once you return from onHandleIntent - i.e. immediately because threadPool.submit is non-blocking. Within the source it calls stopSelf(int) with the startId it got when the service was started.
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
A Service will go into destroyed state if you call stopSelf with the latest (highest) startId. It will keep running if a newer start is in the queue.
If the service goes into destroyed state it will not kill your thread pool because it has no knowledge about it. The problem is that Android now thinks that your service is dead and it will no longer count as a reason to keep your app process. The service running vs destroyed state is essentially just a way to tell Android that there is something going on and you don't want to get destroyed.
If you want to do it the right way you have to keep the service state in sync with what is actually going on.
Is IntentService already something that I want to achieve and should I simply execute my (long running) Runnable code in the onHandleIntent() because this method alread runs on the IntentService worker Thread?
If you are happy with single threaded serial execution yes. That's what onHandleIntent does for you.
If yes, is there a queue limit for intent, since onHandleIntent() could run up to 30 seconds before finishing and handling the next Intent.
There is no limit (it's a linked list as far as I can tell). But there is also nothing that stops you from producing more tasks than it can handle which will ultimately lead to some kind of overflow.

Android service + countdown = not working

Ok this got me really mad. Is there a restriction for services with countdowns?
I tried so many methods to make a countdown timer work in a service,but it always fails. It just never gets to the finish() part!
So is there a restriction with services and countdowns or what? Please help me...
Here is the service:
public class ss extends IntentService {
public ss() {
super("ss");
}
#Override
protected void onHandleIntent(Intent intent) {
new CountdownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
executemymethod(); //it never gets here!
}
}.start();
}
}
As you can see the code is simple and correct,but still the executemymethod(); never really executes! There are no errors... Please give me a solution!
If you want to do this kind of thing you should be using a regular Service and not an IntentService. Here's what the docs say about IntentService:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Since the countdown is asynchronous, the work is complete after you start the countdown timer. The IntentService then finishes immediately, and probably shuts down the thread.

Categories

Resources